aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin37684 -> 37788 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin51096 -> 51440 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_parse.beambin69072 -> 69084 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_scan.beambin30092 -> 30132 bytes
-rw-r--r--erts/doc/src/erlang.xml4
-rw-r--r--erts/emulator/beam/beam_bp.c1
-rw-r--r--erts/emulator/drivers/common/efile_drv.c98
-rw-r--r--erts/etc/common/ct_run.c12
-rw-r--r--erts/etc/unix/run_erl.c2
-rw-r--r--erts/etc/unix/to_erl.c2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_interactive.c2
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin54532 -> 54564 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin93468 -> 93388 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin3612 -> 3644 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin48632 -> 48672 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1444 -> 1476 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin44244 -> 44280 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin70048 -> 70084 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin23404 -> 23444 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin12780 -> 12812 bytes
-rw-r--r--erts/preloaded/src/erlang.erl30
-rw-r--r--erts/test/nt_SUITE.erl3
-rw-r--r--lib/common_test/src/unix_telnet.erl36
-rw-r--r--lib/common_test/test/Makefile3
-rw-r--r--lib/common_test/test/ct_telnet_SUITE.erl122
-rw-r--r--lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl78
-rw-r--r--lib/compiler/src/compile.erl3
-rw-r--r--lib/compiler/src/v3_core.erl51
-rw-r--r--lib/compiler/test/bs_bincomp_SUITE.erl3
-rw-r--r--lib/crypto/c_src/crypto.c275
-rwxr-xr-xlib/crypto/doc/src/crypto.xml102
-rw-r--r--lib/crypto/src/crypto.erl244
-rw-r--r--lib/crypto/test/crypto_SUITE.erl731
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl4
-rw-r--r--lib/diameter/doc/src/diameter.xml2
-rw-r--r--lib/diameter/doc/src/diameter_compile.xml32
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml5
-rw-r--r--lib/diameter/doc/src/diameter_make.xml38
-rw-r--r--lib/diameter/examples/code/redirect_cb.erl4
-rw-r--r--lib/diameter/src/base/diameter.erl2
-rw-r--r--lib/diameter/src/base/diameter_config.erl73
-rw-r--r--lib/diameter/src/base/diameter_lib.erl245
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl29
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl7
-rw-r--r--lib/diameter/test/Makefile5
-rw-r--r--lib/diameter/test/diameter_codec_test.erl6
-rw-r--r--lib/diameter/test/diameter_compiler_SUITE.erl51
-rw-r--r--lib/diameter/test/diameter_config_SUITE.erl261
-rw-r--r--lib/diameter/test/diameter_ct.erl2
-rw-r--r--lib/diameter/test/diameter_examples_SUITE.erl334
-rw-r--r--lib/diameter/test/modules.mk2
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl4
-rw-r--r--lib/hipe/icode/Makefile2
-rw-r--r--lib/hipe/icode/hipe_icode.erl2
-rw-r--r--lib/hipe/icode/hipe_icode.hrl8
-rw-r--r--lib/hipe/icode/hipe_icode_callgraph.erl2
-rw-r--r--lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl18
-rw-r--r--lib/hipe/regalloc/hipe_ls_regalloc.erl2
-rw-r--r--lib/hipe/rtl/Makefile2
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl166
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl4
-rw-r--r--lib/mnesia/test/mnesia.spec2
-rw-r--r--lib/mnesia/test/mnesia_config_test.erl4
-rw-r--r--lib/mnesia/test/mnesia_durability_test.erl16
-rw-r--r--lib/mnesia/test/mnesia_examples_test.erl77
-rw-r--r--lib/mnesia/test/mnesia_recovery_test.erl14
-rw-r--r--lib/odbc/c_src/odbcserver.c2
-rw-r--r--lib/odbc/test/odbc_query_SUITE.erl22
-rw-r--r--lib/odbc/test/oracle.erl27
-rw-r--r--lib/odbc/test/postgres.erl39
-rw-r--r--lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl56
-rw-r--r--lib/orber/doc/src/notes.xml18
-rw-r--r--lib/orber/src/orber_env.erl4
-rw-r--r--lib/orber/vsn.mk3
-rw-r--r--lib/reltool/src/reltool_server.erl39
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl53
-rw-r--r--lib/snmp/include/.gitignore4
-rw-r--r--lib/snmp/priv/mibs/.gitignore1
-rw-r--r--lib/snmp/test/snmp_test_data/.gitignore2
-rw-r--r--lib/ssh/doc/html/.gitignore1
-rw-r--r--lib/ssl/doc/src/ssl.xml72
-rw-r--r--lib/ssl/src/Makefile3
-rw-r--r--lib/ssl/src/ssl.app.src1
-rw-r--r--lib/ssl/src/ssl.erl40
-rw-r--r--lib/ssl/src/ssl_alert.erl4
-rw-r--r--lib/ssl/src/ssl_alert.hrl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl292
-rw-r--r--lib/ssl/src/ssl_cipher.hrl105
-rw-r--r--lib/ssl/src/ssl_connection.erl469
-rw-r--r--lib/ssl/src/ssl_handshake.erl218
-rw-r--r--lib/ssl/src/ssl_handshake.hrl51
-rw-r--r--lib/ssl/src/ssl_internal.hrl3
-rw-r--r--lib/ssl/src/ssl_srp.hrl31
-rw-r--r--lib/ssl/src/ssl_srp_primes.erl506
-rw-r--r--lib/ssl/src/ssl_srp_primes.hrl1
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl47
-rw-r--r--lib/ssl/test/ssl_test_lib.erl64
-rw-r--r--lib/stdlib/doc/src/erl_parse.xml19
-rw-r--r--lib/stdlib/doc/src/sys.xml85
-rw-r--r--lib/stdlib/src/erl_parse.yrl1
-rw-r--r--lib/stdlib/src/erl_scan.erl1
-rw-r--r--lib/stdlib/src/gen_event.erl18
-rw-r--r--lib/stdlib/src/gen_fsm.erl11
-rw-r--r--lib/stdlib/src/gen_server.erl7
-rw-r--r--lib/stdlib/src/sys.erl32
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl28
-rw-r--r--lib/stdlib/test/escript_SUITE.erl2
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl4
-rw-r--r--lib/stdlib/test/gen_event_SUITE.erl47
-rw-r--r--lib/stdlib/test/gen_fsm_SUITE.erl38
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl48
-rw-r--r--lib/stdlib/test/io_proto_SUITE.erl18
-rw-r--r--lib/tools/emacs/erlang-start.el3
-rw-r--r--lib/tools/src/cover.erl11
-rw-r--r--lib/tools/test/cover_SUITE.erl26
-rw-r--r--lib/wx/test/wx_basic_SUITE.erl4
-rw-r--r--lib/wx/test/wx_class_SUITE.erl2
117 files changed, 4775 insertions, 1037 deletions
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index 609d7e703f..e87e6a8555 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam
index 7d11d6576e..7e2960fda2 100644
--- a/bootstrap/lib/compiler/ebin/v3_core.beam
+++ b/bootstrap/lib/compiler/ebin/v3_core.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam
index 849b0671ee..b66feba048 100644
--- a/bootstrap/lib/stdlib/ebin/erl_parse.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam
index 99cb155374..c8da05cb67 100644
--- a/bootstrap/lib/stdlib/ebin/erl_scan.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_scan.beam
Binary files differ
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 06fefa8efb..7dc59ea954 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -4477,6 +4477,7 @@ true</pre>
</func>
<func>
<name name="spawn_opt" arity="2"/>
+ <type name="priority_level" />
<fsummary>Create a new process with a fun as entry point</fsummary>
<desc>
<p>Returns the pid of a new process started by the application
@@ -4490,6 +4491,7 @@ true</pre>
</func>
<func>
<name name="spawn_opt" arity="3"/>
+ <type name="priority_level" />
<fsummary>Create a new process with a fun as entry point on a given node</fsummary>
<desc>
<p>Returns the pid of a new process started by the application
@@ -4501,6 +4503,7 @@ true</pre>
</func>
<func>
<name name="spawn_opt" arity="4"/>
+ <type name="priority_level" />
<fsummary>Create a new process with a function as entry point</fsummary>
<desc>
<p>Works exactly like
@@ -4602,6 +4605,7 @@ true</pre>
</func>
<func>
<name name="spawn_opt" arity="5"/>
+ <type name="priority_level" />
<fsummary>Create a new process with a function as entry point on a given node</fsummary>
<desc>
<p>Returns the pid of a new process started by the application
diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c
index 9b17de34ec..ce025c9b6d 100644
--- a/erts/emulator/beam/beam_bp.c
+++ b/erts/emulator/beam/beam_bp.c
@@ -1580,6 +1580,7 @@ clear_function_break(BeamInstr *pc, Uint break_flags)
}
if (common & ERTS_BPF_META_TRACE) {
MatchSetUnref(bp->meta_ms);
+ bp_meta_unref(bp->meta_pid);
}
if (common & ERTS_BPF_COUNT) {
ASSERT((bp->flags & ERTS_BPF_COUNT_ACTIVE) == 0);
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index a2ef0db83c..6cc1295973 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -397,7 +397,6 @@ struct t_pwritev {
ErlDrvPort port;
ErlDrvPDL q_mtx;
size_t size;
- size_t free_size;
unsigned cnt;
unsigned n;
struct t_pbuf_spec specs[1];
@@ -462,7 +461,6 @@ struct t_data
ErlDrvPort port;
ErlDrvPDL q_mtx;
size_t size;
- size_t free_size;
size_t reply_size;
} writev;
struct t_pwritev pwritev;
@@ -1532,26 +1530,24 @@ static void invoke_writev(void *data) {
}
EF_FREE(iov);
- d->c.writev.free_size = size;
- d->c.writev.size -= size;
if (! d->result_ok) {
d->again = 0;
+ MUTEX_LOCK(d->c.writev.q_mtx);
+ driver_deq(d->c.writev.port, d->c.writev.size);
+ MUTEX_UNLOCK(d->c.writev.q_mtx);
} else {
if (! segment) {
d->again = 0;
}
+ d->c.writev.size -= size;
TRACE_F(("w%lu", (unsigned long)size));
-
+ MUTEX_LOCK(d->c.writev.q_mtx);
+ driver_deq(d->c.writev.port, size);
+ MUTEX_UNLOCK(d->c.writev.q_mtx);
}
- DTRACE_INVOKE_RETURN(FILE_WRITE);
-}
-static void free_writev(void *data) {
- struct t_data *d = data;
- MUTEX_LOCK(d->c.writev.q_mtx);
- driver_deq(d->c.writev.port, d->c.writev.size + d->c.writev.free_size);
- MUTEX_UNLOCK(d->c.writev.q_mtx);
- EF_FREE(d);
+
+ DTRACE_INVOKE_RETURN(FILE_WRITE);
}
static void invoke_pwd(void *data)
@@ -1602,7 +1598,7 @@ static void invoke_pwritev(void *data) {
struct t_pwritev *c = &d->c.pwritev;
size_t p;
int segment;
- size_t size, write_size;
+ size_t size, write_size, written;
DTRACE_INVOKE_SETUP(FILE_PWRITEV);
segment = d->again && c->size >= 2*FILE_SEGMENT_WRITE;
@@ -1622,23 +1618,19 @@ static void invoke_pwritev(void *data) {
if (iovlen < 0)
goto error; /* Port terminated */
- for (iovcnt = 0, c->free_size = 0;
- c->cnt < c->n && iovcnt < iovlen && c->free_size < size;
+ for (iovcnt = 0, written = 0;
+ c->cnt < c->n && iovcnt < iovlen && written < size;
c->cnt++) {
int chop;
write_size = c->specs[c->cnt].size;
if (iov[iovcnt].iov_len - p < write_size) {
- /* Mismatch between pos/size spec and what is queued */
- d->errInfo.posix_errno = EINVAL;
- d->result_ok = 0;
- d->again = 0;
- goto done;
+ goto error;
}
- chop = segment && c->free_size + write_size >= 2*FILE_SEGMENT_WRITE;
+ chop = segment && written + write_size >= 2*FILE_SEGMENT_WRITE;
if (chop) {
- ASSERT(c->free_size < FILE_SEGMENT_WRITE);
+ ASSERT(written < FILE_SEGMENT_WRITE);
write_size = FILE_SEGMENT_WRITE + FILE_SEGMENT_WRITE/2
- - c->free_size;
+ - written;
}
d->result_ok = efile_pwrite(&d->errInfo, (int) d->fd,
(char *)(iov[iovcnt].iov_base) + p,
@@ -1646,15 +1638,15 @@ static void invoke_pwritev(void *data) {
c->specs[c->cnt].offset);
if (! d->result_ok) {
d->again = 0;
- goto done;
+ goto deq_error;
}
- c->free_size += write_size;
+ written += write_size;
c->size -= write_size;
if (chop) {
c->specs[c->cnt].offset += write_size;
c->specs[c->cnt].size -= write_size;
/* Schedule out (d->again != 0) */
- goto done;
+ break;
}
/* Move forward in buffer */
p += write_size;
@@ -1676,25 +1668,28 @@ static void invoke_pwritev(void *data) {
d->errInfo.posix_errno = EINVAL;
d->result_ok = 0;
d->again = 0;
+ deq_error:
+ MUTEX_LOCK(d->c.writev.q_mtx);
+ driver_deq(d->c.pwritev.port, c->size);
+ MUTEX_UNLOCK(d->c.writev.q_mtx);
+
+ goto done;
} else {
- ASSERT(c->free_size == size);
+ ASSERT(written == size);
d->again = 0;
}
- }
+ } else
+ ASSERT(written == FILE_SEGMENT_WRITE);
+
+ MUTEX_LOCK(d->c.writev.q_mtx);
+ driver_deq(d->c.pwritev.port, size);
+ MUTEX_UNLOCK(d->c.writev.q_mtx);
done:
EF_FREE(iov); /* Free our copy of the vector, nothing to restore */
+
DTRACE_INVOKE_RETURN(FILE_PWRITEV);
}
-static void free_pwritev(void *data) {
- struct t_data *d = data;
-
- MUTEX_LOCK(d->c.writev.q_mtx);
- driver_deq(d->c.pwritev.port, d->c.pwritev.free_size + d->c.pwritev.size);
- MUTEX_UNLOCK(d->c.writev.q_mtx);
- EF_FREE(d);
-}
-
static void invoke_flstat(void *data)
{
struct t_data *d = (struct t_data *) data;
@@ -2008,21 +2003,8 @@ static void try_free_read_bin(file_descriptor *desc) {
static int try_again(file_descriptor *desc, struct t_data *d) {
- if (! d->again) {
+ if (! d->again)
return 0;
- }
- switch (d->command) {
- case FILE_WRITE:
- MUTEX_LOCK(d->c.writev.q_mtx);
- driver_deq(d->c.writev.port, d->c.writev.free_size);
- MUTEX_UNLOCK(d->c.writev.q_mtx);
- break;
- case FILE_PWRITEV:
- MUTEX_LOCK(d->c.writev.q_mtx);
- driver_deq(d->c.pwritev.port, d->c.pwritev.free_size);
- MUTEX_UNLOCK(d->c.writev.q_mtx);
- break;
- }
if (desc->timer_state != timer_idle) {
driver_cancel_timer(desc->port);
}
@@ -2078,10 +2060,9 @@ static struct t_data *async_write(file_descriptor *desc, int *errp,
}
#endif
d->reply = reply;
- d->c.writev.free_size = 0;
d->c.writev.reply_size = reply_size;
d->invoke = invoke_writev;
- d->free = free_writev;
+ d->free = free_data;
d->level = 1;
cq_enq(desc, d);
desc->write_buffered = 0;
@@ -2394,7 +2375,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
desc->write_errInfo = d->errInfo;
}
}
- free_writev(data);
+ free_data(data);
break;
case FILE_LSEEK:
if (d->reply) {
@@ -2524,7 +2505,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
} else {
reply_Uint(desc, d->c.pwritev.n);
}
- free_pwritev(data);
+ free_data(data);
break;
case FILE_PREADV:
if (!d->result_ok) {
@@ -2581,7 +2562,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
}
DTRACE6(efile_drv_return, sched_i1, sched_i2, sched_utag,
command, result_ok, posix_errno);
- if (desc->write_buffered != 0 && desc->timer_state == timer_idle) {
+ if (desc->write_buffered != 0 && desc->timer_state == timer_idle ) {
desc->timer_state = timer_write;
driver_set_timer(desc->port, desc->write_delay);
}
@@ -3651,7 +3632,6 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
#ifdef USE_VM_PROBES
dt_i3 = d->c.pwritev.size;
#endif
- d->c.pwritev.free_size = 0;
if (j == 0) {
/* Trivial case - nothing to write */
EF_FREE(d);
@@ -3675,7 +3655,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
MUTEX_UNLOCK(desc->q_mtx);
/* Execute the command */
d->invoke = invoke_pwritev;
- d->free = free_pwritev;
+ d->free = free_data;
d->level = 1;
cq_enq(desc, d);
}
diff --git a/erts/etc/common/ct_run.c b/erts/etc/common/ct_run.c
index 5e5b612a12..853785dcd1 100644
--- a/erts/etc/common/ct_run.c
+++ b/erts/etc/common/ct_run.c
@@ -432,18 +432,6 @@ strsave(char* string)
return p;
}
-/* Instead of making sure basename exists, we do our own */
-static char *simple_basename(char *path)
-{
- char *ptr;
- for (ptr = path; *ptr != '\0'; ++ptr) {
- if (*ptr == '/' || *ptr == '\\') {
- path = ptr + 1;
- }
- }
- return path;
-}
-
static char*
get_default_emulator(char* progname)
{
diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c
index 910be3dce8..a3bcdb85d9 100644
--- a/erts/etc/unix/run_erl.c
+++ b/erts/etc/unix/run_erl.c
@@ -682,7 +682,7 @@ static void pass_on(pid_t childpid)
}
}
- if (!got_some && wfd && buf[0] == '\022') {
+ if (!got_some && wfd && buf[0] == '\014') {
char wbuf[30];
int wlen = sn_printf(wbuf,sizeof(wbuf),"[run_erl v%u-%u]\n",
RUN_ERL_HI_VER, RUN_ERL_LO_VER);
diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c
index 754b349338..094006c5fd 100644
--- a/erts/etc/unix/to_erl.c
+++ b/erts/etc/unix/to_erl.c
@@ -353,7 +353,7 @@ int main(int argc, char **argv)
* at the start of every new to_erl-session.
*/
- if (write(wfd, "\022", 1) < 0) {
+ if (write(wfd, "\014", 1) < 0) {
fprintf(stderr, "Error in writing ^R to FIFO.\n");
}
diff --git a/erts/etc/win32/erlsrv/erlsrv_interactive.c b/erts/etc/win32/erlsrv/erlsrv_interactive.c
index 736eabac79..3f7e20b923 100644
--- a/erts/etc/win32/erlsrv/erlsrv_interactive.c
+++ b/erts/etc/win32/erlsrv/erlsrv_interactive.c
@@ -525,7 +525,7 @@ int do_usage(char *arg0){
"list, give option -args as last option on command line "
"with\n"
"no arguments.\n\n");
- printf("Se Erlang documentation for full description.\n");
+ printf("See Erlang documentation for full description.\n");
return 0;
}
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index a4ddae3d5d..aee6f631cf 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 684659cca1..ea80d47eb6 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 74c08fa4c9..6b2593e427 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 143d5b18b9..7fe1685ef3 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index a6b2fdb985..57dafb9ce7 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 9460f1da6f..7558a713ae 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 8c47d8b611..f836473cb4 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index e6f3995b50..35acb59096 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index cdbaa43d5d..c100d1755b 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 8e4a471a82..a88a8831ea 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -1905,11 +1905,11 @@ setelement(_Index, _Tuple1, _Value) ->
Function :: atom(),
Args :: [term()],
Options :: [Option],
- Option :: link | monitor | {priority, Level}
+ Option :: link | monitor
+ | {priority, Level :: priority_level()}
| {fullsweep_after, Number :: non_neg_integer()}
| {min_heap_size, Size :: non_neg_integer()}
- | {min_bin_vheap_size, VSize :: non_neg_integer()},
- Level :: low | normal | high.
+ | {min_bin_vheap_size, VSize :: non_neg_integer()}.
spawn_opt(_Tuple) ->
erlang:nif_error(undefined).
@@ -2244,11 +2244,11 @@ spawn_monitor(M, F, A) ->
-spec spawn_opt(Fun, Options) -> pid() | {pid(), reference()} when
Fun :: function(),
Options :: [Option],
- Option :: link | monitor | {priority, Level}
+ Option :: link | monitor
+ | {priority, Level :: priority_level()}
| {fullsweep_after, Number :: non_neg_integer()}
| {min_heap_size, Size :: non_neg_integer()}
- | {min_bin_vheap_size, VSize :: non_neg_integer()},
- Level :: low | normal | high.
+ | {min_bin_vheap_size, VSize :: non_neg_integer()}.
spawn_opt(F, O) when erlang:is_function(F) ->
spawn_opt(erlang, apply, [F, []], O);
spawn_opt({M,F}=MF, O) when erlang:is_atom(M), erlang:is_atom(F) ->
@@ -2262,11 +2262,11 @@ spawn_opt(F, O) ->
Node :: node(),
Fun :: function(),
Options :: [Option],
- Option :: link | monitor | {priority, Level}
+ Option :: link | monitor
+ | {priority, Level :: priority_level()}
| {fullsweep_after, Number :: non_neg_integer()}
| {min_heap_size, Size :: non_neg_integer()}
- | {min_bin_vheap_size, VSize :: non_neg_integer()},
- Level :: low | normal | high.
+ | {min_bin_vheap_size, VSize :: non_neg_integer()}.
spawn_opt(N, F, O) when N =:= erlang:node() ->
spawn_opt(F, O);
spawn_opt(N, F, O) when erlang:is_function(F) ->
@@ -2354,11 +2354,11 @@ spawn_link(N,M,F,A) ->
Function :: atom(),
Args :: [term()],
Options :: [Option],
- Option :: link | monitor | {priority, Level}
+ Option :: link | monitor
+ | {priority, Level :: priority_level()}
| {fullsweep_after, Number :: non_neg_integer()}
| {min_heap_size, Size :: non_neg_integer()}
- | {min_bin_vheap_size, VSize :: non_neg_integer()},
- Level :: low | normal | high.
+ | {min_bin_vheap_size, VSize :: non_neg_integer()}.
spawn_opt(M, F, A, Opts) ->
case catch erlang:spawn_opt({M,F,A,Opts}) of
{'EXIT',{Reason,_}} ->
@@ -2374,11 +2374,11 @@ spawn_opt(M, F, A, Opts) ->
Function :: atom(),
Args :: [term()],
Options :: [Option],
- Option :: link | monitor | {priority, Level}
+ Option :: link | monitor
+ | {priority, Level :: priority_level()}
| {fullsweep_after, Number :: non_neg_integer()}
| {min_heap_size, Size :: non_neg_integer()}
- | {min_bin_vheap_size, VSize :: non_neg_integer()},
- Level :: low | normal | high.
+ | {min_bin_vheap_size, VSize :: non_neg_integer()}.
spawn_opt(N, M, F, A, O) when N =:= erlang:node(),
erlang:is_atom(M), erlang:is_atom(F),
erlang:is_list(A), erlang:is_list(O) ->
diff --git a/erts/test/nt_SUITE.erl b/erts/test/nt_SUITE.erl
index f9bd15a0ce..7580a7b364 100644
--- a/erts/test/nt_SUITE.erl
+++ b/erts/test/nt_SUITE.erl
@@ -270,8 +270,11 @@ service_prio(Config) when is_list(Config) ->
?line {ok, OldProcs} = get_current_procs(Config),
?line start_service(Name),
?line {ok, NewProcs} = get_current_procs(Config),
+ timer:sleep(2000),
+ ?line {ok, NewProcs2} = get_current_procs(Config),
?line remove_service(Name),
?line Diff = arrived_procs(OldProcs,NewProcs),
+ io:format("NewProcs ~p~n after sleep~n ~p~n",[Diff, arrived_procs(OldProcs,NewProcs2)]),
%% Not really correct, could fail if another heart is
%% started at the same time...
?line {value, {"heart.exe",_,"high"}} =
diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl
index 99ce92e9f1..71df2ab44e 100644
--- a/lib/common_test/src/unix_telnet.erl
+++ b/lib/common_test/src/unix_telnet.erl
@@ -94,11 +94,16 @@ connect(Ip,Port,Timeout,KeepAlive,Extra) ->
{Username,Password} ->
connect1(Ip,Port,Timeout,KeepAlive,Username,Password);
Name ->
- case get_username_and_password(Name) of
- {ok,{Username,Password}} ->
- connect1(Ip,Port,Timeout,KeepAlive,Username,Password);
- Error ->
- Error
+ case not_require_user_and_pass(Name) of
+ true ->
+ connect_without_username_and_pass(Ip,Port,Timeout,KeepAlive);
+ _ ->
+ case get_username_and_password(Name) of
+ {ok,{Username,Password}} ->
+ connect1(Ip,Port,Timeout,KeepAlive,Username,Password);
+ Error ->
+ Error
+ end
end
end.
@@ -144,6 +149,27 @@ connect1(Ip,Port,Timeout,KeepAlive,Username,Password) ->
end_log(),
Result.
+connect_without_username_and_pass(Ip,Port,Timeout,KeepAlive) ->
+ start_log("unix_telnet:connect"),
+ Result =
+ case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive) of
+ {ok,Pid} ->
+ {ok, Pid};
+ Error ->
+ cont_log("Could not open telnet connection\n~p\n",[Error]),
+ Error
+ end,
+ end_log(),
+ Result.
+
+not_require_user_and_pass(Name) ->
+ case ct:get_config({Name, not_require_user_and_pass}) of
+ undefined ->
+ false;
+ _ ->
+ true
+ end.
+
get_username_and_password(Name) ->
case ct:get_config({Name,username}) of
undefined ->
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index e8607a73af..94569fa87f 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -59,7 +59,8 @@ MODULES= \
ct_group_leader_SUITE \
ct_cover_SUITE \
ct_groups_search_SUITE \
- ct_surefire_SUITE
+ ct_surefire_SUITE \
+ ct_telnet_SUITE
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl
new file mode 100644
index 0000000000..b4f24baa0c
--- /dev/null
+++ b/lib/common_test/test/ct_telnet_SUITE.erl
@@ -0,0 +1,122 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-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
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_telnet_SUITE
+%%%
+%%% Description:
+%%% Edit your ts.unix.config or ts.win32.config before runnings these tests
+%%% Test ct_telnet_SUITE module
+%%%
+%%%-------------------------------------------------------------------
+-module(ct_telnet_SUITE).
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ ct_test_support:init_per_suite(Config).
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ default
+ ].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+default(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join(DataDir, "ct_telnet_basic_SUITE"),
+ Cfg = {unix, ct:get_config(unix)},
+ ok = file:write_file(filename:join(DataDir, "telnet.cfg"), io_lib:write(Cfg) ++ "."),
+ CfgFile = filename:join(DataDir, "telnet.cfg"),
+ {Opts,ERPid} = setup([{suite,Suite},{label,default}, {config, CfgFile}], Config),
+ ok = execute(default, Opts, ERPid, Config).
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+setup(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+execute(Name, Opts, ERPid, Config) ->
+ ok = ct_test_support:run(Opts, Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(Name,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+
+ TestEvents = events_to_check(Name,Config),
+ ct_test_support:verify_events(TestEvents, Events, Config).
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(default,Config) ->
+ {module,_} = code:load_abs(filename:join(?config(data_dir,Config),
+ ct_telnet_basic_SUITE)),
+ TCs = ct_telnet_basic_SUITE:all(),
+ code:purge(ct_telnet_basic_SUITE),
+ code:delete(ct_telnet_basic_SUITE),
+
+ OneTest =
+ [{?eh,start_logging,{'DEF','RUNDIR'}}] ++
+ [{?eh,tc_done,{ct_telnet_basic_SUITE,TC,ok}} || TC <- TCs] ++
+ [{?eh,stop_logging,[]}],
+
+ %% 2 tests (ct:run_test + script_start) is default
+ OneTest ++ OneTest.
diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl
new file mode 100644
index 0000000000..914b95f9cf
--- /dev/null
+++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl
@@ -0,0 +1,78 @@
+%% Modify your ts.unix.config or ts.win32.config file before running these tests
+-module(ct_telnet_basic_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+
+suite() -> [{require,telnet_temp,{unix,[telnet]}}].
+
+all() ->
+ [start_stop, send_and_get, expect, already_closed,
+ cmd, sendf, close_wrong_type].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+start_stop(_Config) ->
+ {ok, Handle} = ct_telnet:open(telnet_temp),
+ ok = ct_telnet:close(Handle),
+ ok.
+send_and_get(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_temp),
+ ok = ct_telnet:send(Handle, "ayt"),
+ {ok, _Data} = ct_telnet:get_data(Handle),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+expect(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_temp),
+ ok = ct_telnet:send(Handle, "echo ayt"),
+ ok = case ct_telnet:expect(Handle, ["ayt"]) of
+ {ok, _} ->
+ ok;
+ {error, {prompt, _}} ->
+ ok
+ end,
+ ok = ct_telnet:close(Handle),
+ ok.
+
+already_closed(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_temp),
+ ok = ct_telnet:close(Handle),
+ {error, already_closed} = ct_telnet:close(Handle),
+ ok.
+
+cmd(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_temp),
+ {ok, _} = ct_telnet:cmd(Handle, "display"),
+ {ok, _} = ct_telnet:cmdf(Handle, "~s ~s", ["set", "bsasdel"]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+sendf(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_temp),
+ ok = ct_telnet:sendf(Handle, "~s", ["ayt"]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+close_wrong_type(_) ->
+ {error, _} = ct_telnet:close(whatever),
+ ok.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 497af2b52c..745f1d5cf9 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -599,7 +599,8 @@ standard_passes() ->
core_passes() ->
%% Optimization and transforms of Core Erlang code.
- [{delay,
+ [{iff,clint0,?pass(core_lint_module)},
+ {delay,
[{unless,no_copt,
[{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/1},
{iff,doldinline,{listing,"oldinline"}},
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 01042cc56f..eea54b30a2 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1187,9 +1187,9 @@ list_gen_pattern(P0, Line, St) ->
bc_initial_size(E, Q, St0) ->
try
- {ElemSzExpr,ElemSzPre,St1} = bc_elem_size(E, St0),
+ {ElemSzExpr,ElemSzPre,EVs,St1} = bc_elem_size(E, St0),
{V,St2} = new_var(St1),
- {GenSzExpr,GenSzPre,St3} = bc_gen_size(Q, St2),
+ {GenSzExpr,GenSzPre,St3} = bc_gen_size(Q, EVs, St2),
case ElemSzExpr of
#c_literal{val=ElemSz} when ElemSz rem 8 =:= 0 ->
NumBytesExpr = #c_literal{val=ElemSz div 8},
@@ -1214,11 +1214,13 @@ bc_initial_size(E, Q, St0) ->
bc_elem_size({bin,_,El}, St0) ->
case bc_elem_size_1(El, 0, []) of
{Bits,[]} ->
- {#c_literal{val=Bits},[],St0};
+ {#c_literal{val=Bits},[],[],St0};
{Bits,Vars0} ->
[{U,V0}|Pairs] = sort(Vars0),
F = bc_elem_size_combine(Pairs, U, [V0], []),
- bc_mul_pairs(F, #c_literal{val=Bits}, [], St0)
+ Vs = [V || {_,#c_var{name=V}} <- Vars0],
+ {E,Pre,St} = bc_mul_pairs(F, #c_literal{val=Bits}, [], St0),
+ {E,Pre,Vs,St}
end.
bc_elem_size_1([{bin_element,_,_,{integer,_,N},Flags}|Es], Bits, Vars) ->
@@ -1260,11 +1262,11 @@ bc_add_list_1([H|T], Pre, E, St0) ->
bc_add_list_1([], Pre, E, St) ->
{E,reverse(Pre),St}.
-bc_gen_size(Q, St) ->
- bc_gen_size_1(Q, #c_literal{val=1}, [], St).
+bc_gen_size(Q, EVs, St) ->
+ bc_gen_size_1(Q, EVs, #c_literal{val=1}, [], St).
-bc_gen_size_1([{generate,L,El,Gen}|Qs], E0, Pre0, St0) ->
- bc_verify_non_filtering(El),
+bc_gen_size_1([{generate,L,El,Gen}|Qs], EVs, E0, Pre0, St0) ->
+ bc_verify_non_filtering(El, EVs),
case Gen of
{var,_,ListVar} ->
Lanno = lineno_anno(L, St0),
@@ -1275,16 +1277,16 @@ bc_gen_size_1([{generate,L,El,Gen}|Qs], E0, Pre0, St0) ->
name=#c_literal{val=length},
args=[#c_var{name=ListVar}]}},
{E,Pre,St} = bc_gen_size_mul(E0, LenVar, [Set|Pre0], St1),
- bc_gen_size_1(Qs, E, Pre, St);
+ bc_gen_size_1(Qs, EVs, E, Pre, St);
_ ->
%% The only expressions we handle is literal lists.
Len = bc_list_length(Gen, 0),
{E,Pre,St} = bc_gen_size_mul(E0, #c_literal{val=Len}, Pre0, St0),
- bc_gen_size_1(Qs, E, Pre, St)
+ bc_gen_size_1(Qs, EVs, E, Pre, St)
end;
-bc_gen_size_1([{b_generate,_,El,Gen}|Qs], E0, Pre0, St0) ->
- bc_verify_non_filtering(El),
- {MatchSzExpr,Pre1,St1} = bc_elem_size(El, St0),
+bc_gen_size_1([{b_generate,_,El,Gen}|Qs], EVs, E0, Pre0, St0) ->
+ bc_verify_non_filtering(El, EVs),
+ {MatchSzExpr,Pre1,_,St1} = bc_elem_size(El, St0),
Pre2 = reverse(Pre1, Pre0),
{ResVar,St2} = new_var(St1),
{BitSizeExpr,Pre3,St3} = bc_gen_bit_size(Gen, Pre2, St2),
@@ -1292,10 +1294,10 @@ bc_gen_size_1([{b_generate,_,El,Gen}|Qs], E0, Pre0, St0) ->
MatchSzExpr)},
Pre4 = [Div|Pre3],
{E,Pre,St} = bc_gen_size_mul(E0, ResVar, Pre4, St3),
- bc_gen_size_1(Qs, E, Pre, St);
-bc_gen_size_1([], E, Pre, St) ->
+ bc_gen_size_1(Qs, EVs, E, Pre, St);
+bc_gen_size_1([], _, E, Pre, St) ->
{E,reverse(Pre),St};
-bc_gen_size_1(_, _, _, _) ->
+bc_gen_size_1(_, _, _, _, _) ->
throw(impossible).
bc_gen_bit_size({var,L,V}, Pre0, St0) ->
@@ -1312,13 +1314,20 @@ bc_gen_bit_size({bin,_,_}=Bin, Pre, St) ->
bc_gen_bit_size(_, _, _) ->
throw(impossible).
-bc_verify_non_filtering({bin,_,Els}) ->
- foreach(fun({bin_element,_,{var,_,_},_,_}) -> ok;
+bc_verify_non_filtering({bin,_,Els}, EVs) ->
+ foreach(fun({bin_element,_,{var,_,V},_,_}) ->
+ case member(V, EVs) of
+ true -> throw(impossible);
+ false -> ok
+ end;
(_) -> throw(impossible)
end, Els);
-bc_verify_non_filtering({var,_,_}) ->
- ok;
-bc_verify_non_filtering(_) ->
+bc_verify_non_filtering({var,_,V}, EVs) ->
+ case member(V, EVs) of
+ true -> throw(impossible);
+ false -> ok
+ end;
+bc_verify_non_filtering(_, _) ->
throw(impossible).
bc_list_length({string,_,Str}, Len) ->
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index d39e340429..451a9b1e3b 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -282,6 +282,9 @@ sizes(Config) when is_list(Config) ->
?line <<1,2,3,0>> = Fun13(7),
?line <<1,2,3,0,0>> = Fun13(8),
+ <<0:3>> = cs_default(<< <<0:S>> || S <- [0,1,2] >>),
+ <<0:3>> = cs_default(<< <<0:S>> || <<S>> <= <<0,1,2>> >>),
+
?line {'EXIT',_} = (catch << <<C:4>> || <<C:8>> <= {1,2,3} >>),
?line cs_end(),
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index e77e5fb8f0..fac77308f6 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2010-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
@@ -136,6 +136,7 @@ static void unload(ErlNifEnv* env, void* priv_data);
/* The NIFs: */
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -207,6 +208,9 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
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 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[]);
@@ -215,6 +219,7 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
/* helpers */
+static void init_algorithms_types(void);
static void init_digest_types(ErlNifEnv* env);
static void hmac_md5(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
@@ -247,6 +252,7 @@ static int library_refc = 0; /* number of users of this dynamic library */
static ErlNifFunc nif_funcs[] = {
{"info_lib", 0, info_lib},
+ {"algorithms", 0, algorithms},
{"md5", 1, md5},
{"md5_init", 0, md5_init},
{"md5_update", 2, md5_update},
@@ -304,7 +310,7 @@ static ErlNifFunc nif_funcs[] = {
{"rand_bytes", 3, rand_bytes_3},
{"strong_rand_mpint_nif", 3, strong_rand_mpint_nif},
{"rand_uniform_nif", 2, rand_uniform_nif},
- {"mod_exp_nif", 3, mod_exp_nif},
+ {"mod_exp_nif", 4, mod_exp_nif},
{"dss_verify", 4, dss_verify},
{"rsa_verify_nif", 4, rsa_verify_nif},
{"aes_cbc_crypt", 4, aes_cbc_crypt},
@@ -321,6 +327,9 @@ static ErlNifFunc nif_funcs[] = {
{"dh_check", 1, dh_check},
{"dh_generate_key_nif", 2, 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},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
@@ -458,6 +467,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_digest = enif_make_atom(env,"digest");
init_digest_types(env);
+ init_algorithms_types();
#ifdef HAVE_DYNAMIC_CRYPTO_LIB
{
@@ -538,6 +548,35 @@ static void unload(ErlNifEnv* env, void* priv_data)
--library_refc;
}
+static int algos_cnt;
+static ERL_NIF_TERM algos[7]; /* increase when extending the list */
+
+static void init_algorithms_types(void)
+{
+ algos_cnt = 0;
+
+ algos[algos_cnt++] = atom_md5;
+ algos[algos_cnt++] = atom_sha;
+ algos[algos_cnt++] = atom_ripemd160;
+#ifdef HAVE_SHA224
+ algos[algos_cnt++] = atom_sha224;
+#endif
+#ifdef HAVE_SHA256
+ algos[algos_cnt++] = atom_sha256;
+#endif
+#ifdef HAVE_SHA384
+ algos[algos_cnt++] = atom_sha384;
+#endif
+#ifdef HAVE_SHA512
+ algos[algos_cnt++] = atom_sha512;
+#endif
+}
+
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ return enif_make_list_from_array(env, algos, algos_cnt);
+}
+
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
/* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */
@@ -1515,6 +1554,17 @@ static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
return 1;
}
+static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
+{
+ ErlNifBinary bin;
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
+ *bnp = BN_bin2bn(bin.data, bin.size, NULL);
+ return 1;
+}
+
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Lo,Hi) */
BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
@@ -1543,16 +1593,19 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
}
static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Base,Exponent,Modulo) */
+{/* (Base,Exponent,Modulo,bin_hdr) */
BIGNUM *bn_base=NULL, *bn_exponent=NULL, *bn_modulo, *bn_result;
BN_CTX *bn_ctx;
unsigned char* ptr;
unsigned dlen;
+ unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */
+ unsigned extra_byte;
ERL_NIF_TERM ret;
- if (!get_bn_from_mpint(env, argv[0], &bn_base)
- || !get_bn_from_mpint(env, argv[1], &bn_exponent)
- || !get_bn_from_mpint(env, argv[2], &bn_modulo)) {
+ if (!get_bn_from_bin(env, argv[0], &bn_base)
+ || !get_bn_from_bin(env, argv[1], &bn_exponent)
+ || !get_bn_from_bin(env, argv[2], &bn_modulo)
+ || !enif_get_uint(env,argv[3],&bin_hdr) || (bin_hdr & ~4)) {
if (bn_base) BN_free(bn_base);
if (bn_exponent) BN_free(bn_exponent);
@@ -1562,9 +1615,14 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
bn_ctx = BN_CTX_new();
BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx);
dlen = BN_num_bytes(bn_result);
- ptr = enif_make_new_binary(env, dlen+4, &ret);
- put_int32(ptr, dlen);
- BN_bn2bin(bn_result, ptr+4);
+ extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen*8-1);
+ ptr = enif_make_new_binary(env, bin_hdr+extra_byte+dlen, &ret);
+ if (bin_hdr) {
+ put_int32(ptr, extra_byte+dlen);
+ ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */
+ ptr += bin_hdr + extra_byte;
+ }
+ BN_bn2bin(bn_result, ptr);
BN_free(bn_result);
BN_CTX_free(bn_ctx);
BN_free(bn_modulo);
@@ -2344,6 +2402,205 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
return ret;
}
+static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Multiplier, Verifier, Generator, Exponent, Prime) */
+ BIGNUM *bn_verifier = NULL;
+ BIGNUM *bn_exponent, *bn_generator, *bn_prime, *bn_multiplier, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[1], &bn_verifier)
+ || !get_bn_from_bin(env, argv[2], &bn_generator)
+ || !get_bn_from_bin(env, argv[3], &bn_exponent)
+ || !get_bn_from_bin(env, argv[4], &bn_prime)) {
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_verifier) BN_free(bn_generator);
+ if (bn_verifier) BN_free(bn_exponent);
+ if (bn_verifier) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_result = BN_new();
+ bn_ctx = BN_CTX_new();
+
+ /* B = k*v + g^b % N */
+
+ /* k * v */
+ BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx);
+
+ /* g^b % N */
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+
+ /* k*v + g^b % N */
+ BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx);
+
+ /* check that B % N != 0, reuse bn_multiplier */
+ BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_multiplier)) {
+ ret = atom_error;
+ } else {
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ }
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+ BN_free(bn_prime);
+ BN_free(bn_generator);
+ BN_free(bn_multiplier);
+ BN_free(bn_exponent);
+ BN_free(bn_verifier);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_client_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
+*/
+ BIGNUM *bn_exponent = NULL, *bn_a = NULL;
+ BIGNUM *bn_u, *bn_multiplier, *bn_exp2, *bn_base,
+ *bn_prime, *bn_generator, *bn_B, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_a)
+ || !get_bn_from_bin(env, argv[1], &bn_u)
+ || !get_bn_from_bin(env, argv[2], &bn_B)
+ || !get_bn_from_bin(env, argv[3], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[4], &bn_generator)
+ || !get_bn_from_bin(env, argv[5], &bn_exponent)
+ || !get_bn_from_bin(env, argv[6], &bn_prime))
+ {
+ if (bn_exponent) BN_free(bn_exponent);
+ if (bn_a) BN_free(bn_a);
+ if (bn_u) BN_free(bn_u);
+ if (bn_B) BN_free(bn_B);
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_generator) BN_free(bn_generator);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that B % N != 0 */
+ BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ BN_free(bn_u);
+ BN_free(bn_B);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (B - (k * g^x)) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx);
+ BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx);
+
+ /* a + (u * x) */
+ bn_exp2 = BN_new();
+ BN_mod_mul(bn_result, bn_u, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_add(bn_exp2, bn_a, bn_result, bn_prime, bn_ctx);
+
+ /* (B - (k * g^x)) ^ (a + (u * x)) % N */
+ BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_multiplier);
+ BN_free(bn_exp2);
+ BN_free(bn_u);
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_B);
+ BN_free(bn_base);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Verifier, b, u, A, Prime) */
+/*
+ <premaster secret> = (A * v^u) ^ b % N
+*/
+ BIGNUM *bn_b = NULL, *bn_verifier = NULL;
+ BIGNUM *bn_prime, *bn_A, *bn_u, *bn_base, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_verifier)
+ || !get_bn_from_bin(env, argv[1], &bn_b)
+ || !get_bn_from_bin(env, argv[2], &bn_u)
+ || !get_bn_from_bin(env, argv[3], &bn_A)
+ || !get_bn_from_bin(env, argv[4], &bn_prime))
+ {
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_b) BN_free(bn_b);
+ if (bn_u) BN_free(bn_u);
+ if (bn_A) BN_free(bn_A);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that A % N != 0 */
+ BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_b);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (A * v^u) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx);
+ BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx);
+
+ /* (A * v^u) ^ b % N */
+ BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_u);
+ BN_free(bn_base);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_free(bn_b);
+ return ret;
+}
+
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, Ivec, Data, IsEncrypt) */
ErlNifBinary key_bin, ivec_bin, data_bin;
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 6b9b2ef207..f30a058ca4 100755
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -63,6 +63,11 @@
<item>
<p>dss: Digital Signature Standard (FIPS 186-2)</p>
</item>
+ <item>
+ <p>srp: Secure Remote Password Protocol (RFC 2945)</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>
@@ -99,6 +104,14 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</desc>
</func>
<func>
+ <name>algorithms() -> [atom()]</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>
@@ -973,7 +986,17 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
using the <c>crypto</c> library.</p>
</desc>
</func>
-
+ <func>
+ <name>mod_exp_prime(N, P, M) -> Result</name>
+ <fsummary>Computes the function: N^P mod M</fsummary>
+ <type>
+ <v>N, P, M = binary()</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>
@@ -1256,8 +1279,85 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</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>
+ <type>
+ <v>Verifier = binary()</v>
+ <d>Parameter v from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso>
+ </d>
+ <v>Generator = binary() </v>
+ <d>Parameter g from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso>
+ </d>
+ <v>Prime = binary() </v>
+ <d>Parameter N from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso>
+ </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 <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso></d>
+ <v>PrivateKey = binary() - generated if not supplied</v>
+ <d>Parameter a or b from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso></d>
+ </type>
+ <desc>
+ <p>Generates SRP public keys</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>
+ <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>
+ </type>
+ <desc>
+ <p>
+ Computes the SRP session key (shared secret). Also used
+ as premaster secret by TLS-SRP ciher suites.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name>exor(Data1, Data2) -> Result</name>
<fsummary>XOR data</fsummary>
<type>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 1328a95e87..1d0a9943c3 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -21,7 +21,7 @@
-module(crypto).
--export([start/0, stop/0, info/0, info_lib/0, version/0]).
+-export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
@@ -57,7 +57,10 @@
-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, mpint/1, erlint/1]).
+-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]).
@@ -88,7 +91,7 @@
strong_rand_bytes,
strong_rand_mpint,
rand_uniform,
- mod_exp,
+ mod_exp, mod_exp_prime,
dss_verify,dss_sign,
rsa_verify,rsa_sign,
rsa_public_encrypt,rsa_private_decrypt,
@@ -109,7 +112,8 @@
hash, hash_init, hash_update, hash_final,
hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info,
rc2_cbc_encrypt, rc2_cbc_decrypt,
- info_lib]).
+ srp_generate_key, srp_compute_key,
+ info_lib, algorithms]).
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'.
@@ -184,6 +188,8 @@ info() ->
info_lib() -> ?nif_stub.
+algorithms() -> ?nif_stub.
+
%% Crypto app version history:
%% (no version): Driver implementation
%% 2.0 : NIF implementation, requires OTP R14
@@ -783,21 +789,24 @@ rand_uniform_pos(_,_) ->
rand_uniform_nif(_From,_To) -> ?nif_stub.
%%
-%% mod_exp - utility for rsa generation
+%% mod_exp - utility for rsa generation and SRP
%%
mod_exp(Base, Exponent, Modulo)
when is_integer(Base), is_integer(Exponent), is_integer(Modulo) ->
- erlint(mod_exp(mpint(Base), mpint(Exponent), mpint(Modulo)));
+ bin_to_int(mod_exp_nif(int_to_bin(Base), int_to_bin(Exponent), int_to_bin(Modulo), 0));
mod_exp(Base, Exponent, Modulo) ->
- case mod_exp_nif(Base,Exponent,Modulo) of
- <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
- <<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
- Whatever ->
- Whatever
+ 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
+ <<0>> -> error;
+ R -> R
end.
-mod_exp_nif(_Base,_Exp,_Mod) -> ?nif_stub.
+
+mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub.
%%
%% DSS, RSA - verify
@@ -1064,50 +1073,205 @@ dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
+
+%%% 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),
+ is_binary(Generator),
+ is_binary(ClientPublic),
+ is_binary(ClientPrivate),
+ is_binary(ServerPublic),
+ 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
+ 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_atom(Version) ->
+ Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
+ srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
+
%%
%% LOCAL FUNCTIONS
%%
+client_srp_gen_key(Private, Generator, Prime) ->
+ case mod_exp_prime(Generator, Private, Prime) of
+ error ->
+ error;
+ Public ->
+ {Public, Private}
+ end.
+
+server_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 ->
+ error;
+ Public ->
+ {Public, Private}
+ end.
+
+srp_multiplier('6a', Generator, Prime) ->
+ %% k = SHA1(N | PAD(g)) from http://srp.stanford.edu/design.html
+ C0 = sha_init(),
+ C1 = sha_update(C0, Prime),
+ C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)),
+ sha_final(C2);
+srp_multiplier('6', _, _) ->
+ <<3/integer>>;
+srp_multiplier('3', _, _) ->
+ <<1/integer>>.
+
+srp_scrambler(Version, ClientPublic, ServerPublic, 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)),
+ sha_final(C2);
+srp_scrambler('3', _, ServerPublic, _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.
+
+srp_pad_length(Width, Length) ->
+ (Width - Length rem Width) rem Width.
+
+srp_pad_to(Width, Binary) ->
+ case srp_pad_length(Width, size(Binary)) of
+ 0 -> Binary;
+ N -> << 0:(N*8), Binary/binary>>
+ end.
+
+srp_server_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+
+srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+
+srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
%% large integer in a binary with 32bit length
%% MP representaion (SSH2)
-mpint(X) when X < 0 ->
- case X of
- -1 ->
- <<0,0,0,1,16#ff>>;
- _ ->
- mpint_neg(X,0,[])
- end;
-mpint(X) ->
- case X of
- 0 ->
- <<0,0,0,0>>;
- _ ->
- mpint_pos(X,0,[])
- end.
+mpint(X) when X < 0 -> mpint_neg(X);
+mpint(X) -> mpint_pos(X).
-define(UINT32(X), X:32/unsigned-big-integer).
-mpint_neg(-1,I,Ds=[MSB|_]) ->
- if MSB band 16#80 =/= 16#80 ->
- <<?UINT32((I+1)), (list_to_binary([255|Ds]))/binary>>;
- true ->
- (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
- end;
-mpint_neg(X,I,Ds) ->
- mpint_neg(X bsr 8,I+1,[(X band 255)|Ds]).
+
+mpint_neg(X) ->
+ Bin = int_to_bin_neg(X, []),
+ Sz = byte_size(Bin),
+ <<?UINT32(Sz), Bin/binary>>.
-mpint_pos(0,I,Ds=[MSB|_]) ->
+mpint_pos(X) ->
+ Bin = int_to_bin_pos(X, []),
+ <<MSB,_/binary>> = Bin,
+ Sz = byte_size(Bin),
if MSB band 16#80 == 16#80 ->
- <<?UINT32((I+1)), (list_to_binary([0|Ds]))/binary>>;
+ <<?UINT32((Sz+1)), 0, Bin/binary>>;
true ->
- (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
- end;
-mpint_pos(X,I,Ds) ->
- mpint_pos(X bsr 8,I+1,[(X band 255)|Ds]).
+ <<?UINT32(Sz), Bin/binary>>
+ end.
+
+int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
+int_to_bin(X) -> int_to_bin_pos(X, []).
+
+%%int_to_bin_pos(X) when X >= 0 ->
+%% int_to_bin_pos(X, []).
+
+int_to_bin_pos(0,Ds=[_|_]) ->
+ list_to_binary(Ds);
+int_to_bin_pos(X,Ds) ->
+ int_to_bin_pos(X bsr 8, [(X band 255)|Ds]).
+
+int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
+ list_to_binary(Ds);
+int_to_bin_neg(X,Ds) ->
+ int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
+
+
+bin_to_int(Bin) ->
+ Bits = bit_size(Bin),
+ <<Integer:Bits/integer>> = Bin,
+ Integer.
%% int from integer in a binary with 32bit length
erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
Bits= MPIntSize * 8,
<<Integer:Bits/integer>> = MPIntValue,
Integer.
+
+mpint_to_bin(<<Len:32, Bin:Len/binary>>) ->
+ Bin.
+
+random_bytes(N) ->
+ try strong_rand_bytes(N) of
+ RandBytes ->
+ RandBytes
+ catch
+ error:low_entropy ->
+ rand_bytes(N)
+ end.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 6f2df0f07b..08ecad3233 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -39,7 +39,10 @@
hmac_update_md5_io/1,
hmac_update_md5_n/1,
hmac_rfc2202/1,
- hmac_rfc4231/1,
+ hmac_rfc4231_sha224/1,
+ hmac_rfc4231_sha256/1,
+ hmac_rfc4231_sha384/1,
+ hmac_rfc4231_sha512/1,
ripemd160/1,
ripemd160_update/1,
sha256/1,
@@ -72,6 +75,7 @@
dsa_sign_hash_test/1,
rsa_encrypt_decrypt/1,
dh/1,
+ srp3/1, srp6/1, srp6a/1,
exor_test/1,
rc4_test/1,
rc4_stream_test/1,
@@ -93,14 +97,15 @@ groups() ->
sha256, sha256_update, sha512, sha512_update,
hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512,
hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5,
- hmac_rfc2202, hmac_rfc4231,
+ hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256,
+ hmac_rfc4231_sha384, hmac_rfc4231_sha512,
des_cbc, aes_cfb, aes_cbc,
des_cfb, des_cfb_iter, des3_cbc, des3_cfb, rc2_cbc,
aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb,
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, exor_test,
+ rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, exor_test,
rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
smp]}].
@@ -363,8 +368,7 @@ hmac_update_sha256(doc) ->
hmac_update_sha256(suite) ->
[];
hmac_update_sha256(Config) when is_list(Config) ->
- if_098(fun() -> hmac_update_sha256_do() end).
-
+ if_supported(sha256, fun() -> hmac_update_sha256_do() end).
hmac_update_sha256_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -386,7 +390,7 @@ hmac_update_sha512(doc) ->
hmac_update_sha512(suite) ->
[];
hmac_update_sha512(Config) when is_list(Config) ->
- if_098(fun() -> hmac_update_sha512_do() end).
+ if_supported(sha512, fun() -> hmac_update_sha512_do() end).
hmac_update_sha512_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -582,366 +586,192 @@ hmac_rfc2202_sha() ->
?line m(Case7Exp, Case7Mac_1),
?line m(Case7Exp, Case7Mac_2).
-hmac_rfc4231(doc) ->
- ["Generate an HMAC using crypto:shaXXX_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+hmac_rfc4231_sha224(doc) ->
+ ["Generate an HMAC using crypto:sha224_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
"Testvectors are take from RFC4231." ];
-hmac_rfc4231(suite) ->
+hmac_rfc4231_sha224(suite) ->
[];
-hmac_rfc4231(Config) when is_list(Config) ->
- if_098(fun() -> hmac_rfc4231_do() end).
+hmac_rfc4231_sha224(Config) when is_list(Config) ->
+ if_supported(sha224, fun() -> hmac_rfc4231_sha224_do() end).
-hmac_rfc4231_do() ->
- %% Test Case 1
- Case1Key = binary:copy(<<16#0b>>, 20),
- Case1Data = <<"Hi There">>,
- Case1Exp224 = hexstr2bin("896fb1128abbdf196832107cd49df33f"
- "47b4b1169912ba4f53684b22"),
- Case1Exp256 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
- "881dc200c9833da726e9376c2e32cff7"),
- Case1Exp384 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
- "15f9dadbe4101ec682aa034c7cebc59c"
- "faea9ea9076ede7f4af152e8b2fa9cb6"),
- Case1Exp512 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
- "2379f4e2ce4ec2787ad0b30545e17cde"
- "daa833b7d6b8a702038b274eaea3f4e4"
- "be9d914eeb61f1702e696c203a126854"),
-
- ?line Case1Ctx224 = crypto:hmac_init(sha224, Case1Key),
- ?line Case1Ctx224_2 = crypto:hmac_update(Case1Ctx224, Case1Data),
- ?line Case1Mac224_1 = crypto:hmac_final(Case1Ctx224_2),
- ?line Case1Mac224_2 = crypto:sha224_mac(Case1Key, Case1Data),
- ?line Case1Mac224_3 = crypto:hmac(sha224, Case1Key, Case1Data),
- ?line m(Case1Exp224, Case1Mac224_1),
- ?line m(Case1Exp224, Case1Mac224_2),
- ?line m(Case1Exp224, Case1Mac224_3),
-
- ?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key),
- ?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data),
- ?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2),
- ?line Case1Mac256_2 = crypto:sha256_mac(Case1Key, Case1Data),
- ?line Case1Mac256_3 = crypto:hmac(sha256, Case1Key, Case1Data),
- ?line m(Case1Exp256, Case1Mac256_1),
- ?line m(Case1Exp256, Case1Mac256_2),
- ?line m(Case1Exp256, Case1Mac256_3),
-
- ?line Case1Ctx384 = crypto:hmac_init(sha384, Case1Key),
- ?line Case1Ctx384_2 = crypto:hmac_update(Case1Ctx384, Case1Data),
- ?line Case1Mac384_1 = crypto:hmac_final(Case1Ctx384_2),
- ?line Case1Mac384_2 = crypto:sha384_mac(Case1Key, Case1Data),
- ?line Case1Mac384_3 = crypto:hmac(sha384, Case1Key, Case1Data),
- ?line m(Case1Exp384, Case1Mac384_1),
- ?line m(Case1Exp384, Case1Mac384_2),
- ?line m(Case1Exp384, Case1Mac384_3),
-
- ?line Case1Ctx512 = crypto:hmac_init(sha512, Case1Key),
- ?line Case1Ctx512_2 = crypto:hmac_update(Case1Ctx512, Case1Data),
- ?line Case1Mac512_1 = crypto:hmac_final(Case1Ctx512_2),
- ?line Case1Mac512_2 = crypto:sha512_mac(Case1Key, Case1Data),
- ?line Case1Mac512_3 = crypto:hmac(sha512, Case1Key, Case1Data),
- ?line m(Case1Exp512, Case1Mac512_1),
- ?line m(Case1Exp512, Case1Mac512_2),
- ?line m(Case1Exp512, Case1Mac512_3),
-
- %% Test Case 2
- Case2Key = <<"Jefe">>,
- Case2Data = <<"what do ya want for nothing?">>,
- Case2Exp224 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
- "8bbea2a39e6148008fd05e44"),
- Case2Exp256 = hexstr2bin("5bdcc146bf60754e6a042426089575c7"
- "5a003f089d2739839dec58b964ec3843"),
- Case2Exp384 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
- "9c7ef464f5a01b47e42ec3736322445e"
- "8e2240ca5e69e2c78b3239ecfab21649"),
- Case2Exp512 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
- "87bd64222e831fd610270cd7ea250554"
- "9758bf75c05a994a6d034f65f8f0e6fd"
- "caeab1a34d4a6b4b636e070a38bce737"),
-
- ?line Case2Ctx224 = crypto:hmac_init(sha224, Case2Key),
- ?line Case2Ctx224_2 = crypto:hmac_update(Case2Ctx224, Case2Data),
- ?line Case2Mac224_1 = crypto:hmac_final(Case2Ctx224_2),
- ?line Case2Mac224_2 = crypto:sha224_mac(Case2Key, Case2Data),
- ?line Case2Mac224_3 = crypto:hmac(sha224, Case2Key, Case2Data),
- ?line m(Case2Exp224, Case2Mac224_1),
- ?line m(Case2Exp224, Case2Mac224_2),
- ?line m(Case2Exp224, Case2Mac224_3),
-
- ?line Case2Ctx256 = crypto:hmac_init(sha256, Case2Key),
- ?line Case2Ctx256_2 = crypto:hmac_update(Case2Ctx256, Case2Data),
- ?line Case2Mac256_1 = crypto:hmac_final(Case2Ctx256_2),
- ?line Case2Mac256_2 = crypto:sha256_mac(Case2Key, Case2Data),
- ?line Case2Mac256_3 = crypto:hmac(sha256, Case2Key, Case2Data),
- ?line m(Case2Exp256, Case2Mac256_1),
- ?line m(Case2Exp256, Case2Mac256_2),
- ?line m(Case2Exp256, Case2Mac256_3),
-
- ?line Case2Ctx384 = crypto:hmac_init(sha384, Case2Key),
- ?line Case2Ctx384_2 = crypto:hmac_update(Case2Ctx384, Case2Data),
- ?line Case2Mac384_1 = crypto:hmac_final(Case2Ctx384_2),
- ?line Case2Mac384_2 = crypto:sha384_mac(Case2Key, Case2Data),
- ?line Case2Mac384_3 = crypto:hmac(sha384, Case2Key, Case2Data),
- ?line m(Case2Exp384, Case2Mac384_1),
- ?line m(Case2Exp384, Case2Mac384_2),
- ?line m(Case2Exp384, Case2Mac384_3),
-
- ?line Case2Ctx512 = crypto:hmac_init(sha512, Case2Key),
- ?line Case2Ctx512_2 = crypto:hmac_update(Case2Ctx512, Case2Data),
- ?line Case2Mac512_1 = crypto:hmac_final(Case2Ctx512_2),
- ?line Case2Mac512_2 = crypto:sha512_mac(Case2Key, Case2Data),
- ?line Case2Mac512_3 = crypto:hmac(sha512, Case2Key, Case2Data),
- ?line m(Case2Exp512, Case2Mac512_1),
- ?line m(Case2Exp512, Case2Mac512_2),
- ?line m(Case2Exp512, Case2Mac512_3),
-
- %% Test Case 3
- Case3Key = binary:copy(<<16#aa>>, 20),
- Case3Data = binary:copy(<<16#dd>>, 50),
- Case3Exp224 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
- "9365b0c1f65d69d1ec8333ea"),
- Case3Exp256 = hexstr2bin("773ea91e36800e46854db8ebd09181a7"
- "2959098b3ef8c122d9635514ced565fe"),
- Case3Exp384 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
- "0aa635d947ac9febe83ef4e55966144b"
- "2a5ab39dc13814b94e3ab6e101a34f27"),
- Case3Exp512 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
- "b1b5dbdd8ee81a3655f83e33b2279d39"
- "bf3e848279a722c806b485a47e67c807"
- "b946a337bee8942674278859e13292fb"),
-
- ?line Case3Ctx224 = crypto:hmac_init(sha224, Case3Key),
- ?line Case3Ctx224_2 = crypto:hmac_update(Case3Ctx224, Case3Data),
- ?line Case3Mac224_1 = crypto:hmac_final(Case3Ctx224_2),
- ?line Case3Mac224_2 = crypto:sha224_mac(Case3Key, Case3Data),
- ?line Case3Mac224_3 = crypto:hmac(sha224, Case3Key, Case3Data),
- ?line m(Case3Exp224, Case3Mac224_1),
- ?line m(Case3Exp224, Case3Mac224_2),
- ?line m(Case3Exp224, Case3Mac224_3),
-
- ?line Case3Ctx256 = crypto:hmac_init(sha256, Case3Key),
- ?line Case3Ctx256_2 = crypto:hmac_update(Case3Ctx256, Case3Data),
- ?line Case3Mac256_1 = crypto:hmac_final(Case3Ctx256_2),
- ?line Case3Mac256_2 = crypto:sha256_mac(Case3Key, Case3Data),
- ?line Case3Mac256_3 = crypto:hmac(sha256, Case3Key, Case3Data),
- ?line m(Case3Exp256, Case3Mac256_1),
- ?line m(Case3Exp256, Case3Mac256_2),
- ?line m(Case3Exp256, Case3Mac256_3),
-
- ?line Case3Ctx384 = crypto:hmac_init(sha384, Case3Key),
- ?line Case3Ctx384_2 = crypto:hmac_update(Case3Ctx384, Case3Data),
- ?line Case3Mac384_1 = crypto:hmac_final(Case3Ctx384_2),
- ?line Case3Mac384_2 = crypto:sha384_mac(Case3Key, Case3Data),
- ?line Case3Mac384_3 = crypto:hmac(sha384, Case3Key, Case3Data),
- ?line m(Case3Exp384, Case3Mac384_1),
- ?line m(Case3Exp384, Case3Mac384_2),
- ?line m(Case3Exp384, Case3Mac384_3),
-
- ?line Case3Ctx512 = crypto:hmac_init(sha512, Case3Key),
- ?line Case3Ctx512_2 = crypto:hmac_update(Case3Ctx512, Case3Data),
- ?line Case3Mac512_1 = crypto:hmac_final(Case3Ctx512_2),
- ?line Case3Mac512_2 = crypto:sha512_mac(Case3Key, Case3Data),
- ?line Case3Mac512_3 = crypto:hmac(sha512, Case3Key, Case3Data),
- ?line m(Case3Exp512, Case3Mac512_1),
- ?line m(Case3Exp512, Case3Mac512_2),
- ?line m(Case3Exp512, Case3Mac512_3),
-
- %% Test Case 4
- Case4Key = list_to_binary(lists:seq(1, 16#19)),
- Case4Data = binary:copy(<<16#cd>>, 50),
- Case4Exp224 = hexstr2bin("6c11506874013cac6a2abc1bb382627c"
- "ec6a90d86efc012de7afec5a"),
- Case4Exp256 = hexstr2bin("82558a389a443c0ea4cc819899f2083a"
- "85f0faa3e578f8077a2e3ff46729665b"),
- Case4Exp384 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
- "7a9981480850009cc5577c6e1f573b4e"
- "6801dd23c4a7d679ccf8a386c674cffb"),
- Case4Exp512 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
- "e576d97ff94b872de76f8050361ee3db"
- "a91ca5c11aa25eb4d679275cc5788063"
- "a5f19741120c4f2de2adebeb10a298dd"),
-
- ?line Case4Ctx224 = crypto:hmac_init(sha224, Case4Key),
- ?line Case4Ctx224_2 = crypto:hmac_update(Case4Ctx224, Case4Data),
- ?line Case4Mac224_1 = crypto:hmac_final(Case4Ctx224_2),
- ?line Case4Mac224_2 = crypto:sha224_mac(Case4Key, Case4Data),
- ?line Case4Mac224_3 = crypto:hmac(sha224, Case4Key, Case4Data),
- ?line m(Case4Exp224, Case4Mac224_1),
- ?line m(Case4Exp224, Case4Mac224_2),
- ?line m(Case4Exp224, Case4Mac224_3),
-
- ?line Case4Ctx256 = crypto:hmac_init(sha256, Case4Key),
- ?line Case4Ctx256_2 = crypto:hmac_update(Case4Ctx256, Case4Data),
- ?line Case4Mac256_1 = crypto:hmac_final(Case4Ctx256_2),
- ?line Case4Mac256_2 = crypto:sha256_mac(Case4Key, Case4Data),
- ?line Case4Mac256_3 = crypto:hmac(sha256, Case4Key, Case4Data),
- ?line m(Case4Exp256, Case4Mac256_1),
- ?line m(Case4Exp256, Case4Mac256_2),
- ?line m(Case4Exp256, Case4Mac256_3),
-
- ?line Case4Ctx384 = crypto:hmac_init(sha384, Case4Key),
- ?line Case4Ctx384_2 = crypto:hmac_update(Case4Ctx384, Case4Data),
- ?line Case4Mac384_1 = crypto:hmac_final(Case4Ctx384_2),
- ?line Case4Mac384_2 = crypto:sha384_mac(Case4Key, Case4Data),
- ?line Case4Mac384_3 = crypto:hmac(sha384, Case4Key, Case4Data),
- ?line m(Case4Exp384, Case4Mac384_1),
- ?line m(Case4Exp384, Case4Mac384_2),
- ?line m(Case4Exp384, Case4Mac384_3),
-
- ?line Case4Ctx512 = crypto:hmac_init(sha512, Case4Key),
- ?line Case4Ctx512_2 = crypto:hmac_update(Case4Ctx512, Case4Data),
- ?line Case4Mac512_1 = crypto:hmac_final(Case4Ctx512_2),
- ?line Case4Mac512_2 = crypto:sha512_mac(Case4Key, Case4Data),
- ?line Case4Mac512_3 = crypto:hmac(sha512, Case4Key, Case4Data),
- ?line m(Case4Exp512, Case4Mac512_1),
- ?line m(Case4Exp512, Case4Mac512_2),
- ?line m(Case4Exp512, Case4Mac512_3),
-
- %% Test Case 5
- Case5Key = binary:copy(<<16#0c>>, 20),
- Case5Data = <<"Test With Truncation">>,
- Case5Exp224 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
- Case5Exp256 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
- Case5Exp384 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
- Case5Exp512 = hexstr2bin("415fad6271580a531d4179bc891d87a6"),
-
- ?line Case5Ctx224 = crypto:hmac_init(sha224, Case5Key),
- ?line Case5Ctx224_2 = crypto:hmac_update(Case5Ctx224, Case5Data),
- ?line Case5Mac224_1 = crypto:hmac_final_n(Case5Ctx224_2, 16),
- ?line Case5Mac224_2 = crypto:sha224_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac224_3 = crypto:hmac(sha224, Case5Key, Case5Data, 16),
- ?line m(Case5Exp224, Case5Mac224_1),
- ?line m(Case5Exp224, Case5Mac224_2),
- ?line m(Case5Exp224, Case5Mac224_3),
-
- ?line Case5Ctx256 = crypto:hmac_init(sha256, Case5Key),
- ?line Case5Ctx256_2 = crypto:hmac_update(Case5Ctx256, Case5Data),
- ?line Case5Mac256_1 = crypto:hmac_final_n(Case5Ctx256_2, 16),
- ?line Case5Mac256_2 = crypto:sha256_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac256_3 = crypto:hmac(sha256, Case5Key, Case5Data, 16),
- ?line m(Case5Exp256, Case5Mac256_1),
- ?line m(Case5Exp256, Case5Mac256_2),
- ?line m(Case5Exp256, Case5Mac256_3),
-
- ?line Case5Ctx384 = crypto:hmac_init(sha384, Case5Key),
- ?line Case5Ctx384_2 = crypto:hmac_update(Case5Ctx384, Case5Data),
- ?line Case5Mac384_1 = crypto:hmac_final_n(Case5Ctx384_2, 16),
- ?line Case5Mac384_2 = crypto:sha384_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac384_3 = crypto:hmac(sha384, Case5Key, Case5Data, 16),
- ?line m(Case5Exp384, Case5Mac384_1),
- ?line m(Case5Exp384, Case5Mac384_2),
- ?line m(Case5Exp384, Case5Mac384_3),
-
- ?line Case5Ctx512 = crypto:hmac_init(sha512, Case5Key),
- ?line Case5Ctx512_2 = crypto:hmac_update(Case5Ctx512, Case5Data),
- ?line Case5Mac512_1 = crypto:hmac_final_n(Case5Ctx512_2, 16),
- ?line Case5Mac512_2 = crypto:sha512_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac512_3 = crypto:hmac(sha512, Case5Key, Case5Data, 16),
- ?line m(Case5Exp512, Case5Mac512_1),
- ?line m(Case5Exp512, Case5Mac512_2),
- ?line m(Case5Exp512, Case5Mac512_3),
-
- %% Test Case 6
- Case6Key = binary:copy(<<16#aa>>, 131),
- Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- Case6Exp224 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
- "d499f112f2d2b7273fa6870e"),
- Case6Exp256 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
- "8e0bc6213728c5140546040f0ee37f54"),
- Case6Exp384 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
- "4f9ef1012a2b588f3cd11f05033ac4c6"
- "0c2ef6ab4030fe8296248df163f44952"),
- Case6Exp512 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
- "9b46d1f41b4aeec1121b013783f8f352"
- "6b56d037e05f2598bd0fd2215d6a1e52"
- "95e64f73f63f0aec8b915a985d786598"),
-
- ?line Case6Ctx224 = crypto:hmac_init(sha224, Case6Key),
- ?line Case6Ctx224_2 = crypto:hmac_update(Case6Ctx224, Case6Data),
- ?line Case6Mac224_1 = crypto:hmac_final(Case6Ctx224_2),
- ?line Case6Mac224_2 = crypto:sha224_mac(Case6Key, Case6Data),
- ?line Case6Mac224_3 = crypto:hmac(sha224, Case6Key, Case6Data),
- ?line m(Case6Exp224, Case6Mac224_1),
- ?line m(Case6Exp224, Case6Mac224_2),
- ?line m(Case6Exp224, Case6Mac224_3),
-
- ?line Case6Ctx256 = crypto:hmac_init(sha256, Case6Key),
- ?line Case6Ctx256_2 = crypto:hmac_update(Case6Ctx256, Case6Data),
- ?line Case6Mac256_1 = crypto:hmac_final(Case6Ctx256_2),
- ?line Case6Mac256_2 = crypto:sha256_mac(Case6Key, Case6Data),
- ?line Case6Mac256_3 = crypto:hmac(sha256, Case6Key, Case6Data),
- ?line m(Case6Exp256, Case6Mac256_1),
- ?line m(Case6Exp256, Case6Mac256_2),
- ?line m(Case6Exp256, Case6Mac256_3),
-
- ?line Case6Ctx384 = crypto:hmac_init(sha384, Case6Key),
- ?line Case6Ctx384_2 = crypto:hmac_update(Case6Ctx384, Case6Data),
- ?line Case6Mac384_1 = crypto:hmac_final(Case6Ctx384_2),
- ?line Case6Mac384_2 = crypto:sha384_mac(Case6Key, Case6Data),
- ?line Case6Mac384_3 = crypto:hmac(sha384, Case6Key, Case6Data),
- ?line m(Case6Exp384, Case6Mac384_1),
- ?line m(Case6Exp384, Case6Mac384_2),
- ?line m(Case6Exp384, Case6Mac384_3),
-
- ?line Case6Ctx512 = crypto:hmac_init(sha512, Case6Key),
- ?line Case6Ctx512_2 = crypto:hmac_update(Case6Ctx512, Case6Data),
- ?line Case6Mac512_1 = crypto:hmac_final(Case6Ctx512_2),
- ?line Case6Mac512_2 = crypto:sha512_mac(Case6Key, Case6Data),
- ?line Case6Mac512_3 = crypto:hmac(sha512, Case6Key, Case6Data),
- ?line m(Case6Exp512, Case6Mac512_1),
- ?line m(Case6Exp512, Case6Mac512_2),
- ?line m(Case6Exp512, Case6Mac512_3),
-
+hmac_rfc4231_sha256(doc) ->
+ ["Generate an HMAC using crypto:sha256_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha256(suite) ->
+ [];
+hmac_rfc4231_sha256(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> hmac_rfc4231_sha256_do() end).
+
+hmac_rfc4231_sha384(doc) ->
+ ["Generate an HMAC using crypto:sha384_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha384(suite) ->
+ [];
+hmac_rfc4231_sha384(Config) when is_list(Config) ->
+ if_supported(sha384, fun() -> hmac_rfc4231_sha384_do() end).
+
+hmac_rfc4231_sha512(doc) ->
+ ["Generate an HMAC using crypto:sha512_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+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) ->
+ %% Test 1
+ Key = binary:copy(<<16#0b>>, 20),
+ Data = <<"Hi There">>,
+ hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, HashFun, 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, HashFun, 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, HashFun, 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, HashFun, 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, HashFun, 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, HashFun, case7, Exp) ->
%% Test Case 7
- Case7Key = binary:copy(<<16#aa>>, 131),
- Case7Data = <<"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.">>,
- Case7Exp224 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
- "946770db9c2b95c9f6f565d1"),
- Case7Exp256 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
- "bfdc63644f0713938a7f51535c3a35e2"),
- Case7Exp384 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
- "602420feb0b8fb9adccebb82461e99c5"
- "a678cc31e799176d3860e6110c46523e"),
- Case7Exp512 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
- "debd71f8867289865df5a32d20cdc944"
- "b6022cac3c4982b10d5eeb55c3e4de15"
- "134676fb6de0446065c97440fa8c6a58"),
-
- ?line Case7Ctx224 = crypto:hmac_init(sha224, Case7Key),
- ?line Case7Ctx224_2 = crypto:hmac_update(Case7Ctx224, Case7Data),
- ?line Case7Mac224_1 = crypto:hmac_final(Case7Ctx224_2),
- ?line Case7Mac224_2 = crypto:sha224_mac(Case7Key, Case7Data),
- ?line Case7Mac224_3 = crypto:hmac(sha224, Case7Key, Case7Data),
- ?line m(Case7Exp224, Case7Mac224_1),
- ?line m(Case7Exp224, Case7Mac224_2),
- ?line m(Case7Exp224, Case7Mac224_3),
-
- ?line Case7Ctx256 = crypto:hmac_init(sha256, Case7Key),
- ?line Case7Ctx256_2 = crypto:hmac_update(Case7Ctx256, Case7Data),
- ?line Case7Mac256_1 = crypto:hmac_final(Case7Ctx256_2),
- ?line Case7Mac256_2 = crypto:sha256_mac(Case7Key, Case7Data),
- ?line Case7Mac256_3 = crypto:hmac(sha256, Case7Key, Case7Data),
- ?line m(Case7Exp256, Case7Mac256_1),
- ?line m(Case7Exp256, Case7Mac256_2),
- ?line m(Case7Exp256, Case7Mac256_3),
-
- ?line Case7Ctx384 = crypto:hmac_init(sha384, Case7Key),
- ?line Case7Ctx384_2 = crypto:hmac_update(Case7Ctx384, Case7Data),
- ?line Case7Mac384_1 = crypto:hmac_final(Case7Ctx384_2),
- ?line Case7Mac384_2 = crypto:sha384_mac(Case7Key, Case7Data),
- ?line Case7Mac384_3 = crypto:hmac(sha384, Case7Key, Case7Data),
- ?line m(Case7Exp384, Case7Mac384_1),
- ?line m(Case7Exp384, Case7Mac384_2),
- ?line m(Case7Exp384, Case7Mac384_3),
-
- ?line Case7Ctx512 = crypto:hmac_init(sha512, Case7Key),
- ?line Case7Ctx512_2 = crypto:hmac_update(Case7Ctx512, Case7Data),
- ?line Case7Mac512_1 = crypto:hmac_final(Case7Ctx512_2),
- ?line Case7Mac512_2 = crypto:sha512_mac(Case7Key, Case7Data),
- ?line Case7Mac512_3 = crypto:hmac(sha512, Case7Key, Case7Data),
- ?line m(Case7Exp512, Case7Mac512_1),
- ?line m(Case7Exp512, Case7Mac512_2),
- ?line m(Case7Exp512, Case7Mac512_3).
+ 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, HashFun, 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) ->
+ ?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() ->
+ Case1 = hexstr2bin("896fb1128abbdf196832107cd49df33f"
+ "47b4b1169912ba4f53684b22"),
+ Case2 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
+ "8bbea2a39e6148008fd05e44"),
+ Case3 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
+ "9365b0c1f65d69d1ec8333ea"),
+ Case4 = hexstr2bin("6c11506874013cac6a2abc1bb382627c"
+ "ec6a90d86efc012de7afec5a"),
+ Case5 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
+ Case6 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
+ "d499f112f2d2b7273fa6870e"),
+ Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
+ "946770db9c2b95c9f6f565d1"),
+ hmac_rfc4231_cases_do(sha224, sha224_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha256_do() ->
+ Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
+ "881dc200c9833da726e9376c2e32cff7"),
+ Case2 = hexstr2bin("5bdcc146bf60754e6a042426089575c7"
+ "5a003f089d2739839dec58b964ec3843"),
+ Case3 = hexstr2bin("773ea91e36800e46854db8ebd09181a7"
+ "2959098b3ef8c122d9635514ced565fe"),
+ Case4 = hexstr2bin("82558a389a443c0ea4cc819899f2083a"
+ "85f0faa3e578f8077a2e3ff46729665b"),
+ Case5 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
+ Case6 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
+ "8e0bc6213728c5140546040f0ee37f54"),
+ Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
+ "bfdc63644f0713938a7f51535c3a35e2"),
+ hmac_rfc4231_cases_do(sha256, sha256_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha384_do() ->
+ Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
+ "15f9dadbe4101ec682aa034c7cebc59c"
+ "faea9ea9076ede7f4af152e8b2fa9cb6"),
+ Case2 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
+ "9c7ef464f5a01b47e42ec3736322445e"
+ "8e2240ca5e69e2c78b3239ecfab21649"),
+ Case3 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
+ "0aa635d947ac9febe83ef4e55966144b"
+ "2a5ab39dc13814b94e3ab6e101a34f27"),
+ Case4 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
+ "7a9981480850009cc5577c6e1f573b4e"
+ "6801dd23c4a7d679ccf8a386c674cffb"),
+ Case5 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
+ Case6 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
+ "4f9ef1012a2b588f3cd11f05033ac4c6"
+ "0c2ef6ab4030fe8296248df163f44952"),
+ Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
+ "602420feb0b8fb9adccebb82461e99c5"
+ "a678cc31e799176d3860e6110c46523e"),
+ hmac_rfc4231_cases_do(sha384, sha384_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha512_do() ->
+ Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
+ "2379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4"
+ "be9d914eeb61f1702e696c203a126854"),
+ Case2 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
+ "87bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fd"
+ "caeab1a34d4a6b4b636e070a38bce737"),
+ Case3 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
+ "b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807"
+ "b946a337bee8942674278859e13292fb"),
+ Case4 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
+ "e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063"
+ "a5f19741120c4f2de2adebeb10a298dd"),
+ Case5 = hexstr2bin("415fad6271580a531d4179bc891d87a6"),
+ Case6 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
+ "9b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e52"
+ "95e64f73f63f0aec8b915a985d786598"),
+ Case7 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
+ "debd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15"
+ "134676fb6de0446065c97440fa8c6a58"),
+ hmac_rfc4231_cases_do(sha512, sha512_mac, [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, _HashFun, _, []) ->
+ 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_update_md5_io(doc) ->
["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
@@ -1025,7 +855,7 @@ sha256(doc) ->
sha256(suite) ->
[];
sha256(Config) when is_list(Config) ->
- if_098(fun() -> sha256_do() end).
+ if_supported(sha256, fun() -> sha256_do() end).
sha256_do() ->
?line m(crypto:sha256("abc"),
@@ -1044,7 +874,7 @@ sha256_update(doc) ->
sha256_update(suite) ->
[];
sha256_update(Config) when is_list(Config) ->
- if_098(fun() -> sha256_update_do() end).
+ if_supported(sha256, fun() -> sha256_update_do() end).
sha256_update_do() ->
?line Ctx = crypto:sha256_init(),
@@ -1063,7 +893,7 @@ sha512(doc) ->
sha512(suite) ->
[];
sha512(Config) when is_list(Config) ->
- if_098(fun() -> sha512_do() end).
+ if_supported(sha512, fun() -> sha512_do() end).
sha512_do() ->
?line m(crypto:sha512("abc"),
@@ -1084,7 +914,7 @@ sha512_update(doc) ->
sha512_update(suite) ->
[];
sha512_update(Config) when is_list(Config) ->
- if_098(fun() -> sha512_update_do() end).
+ if_supported(sha512, fun() -> sha512_update_do() end).
sha512_update_do() ->
?line Ctx = crypto:sha512_init(),
@@ -2017,6 +1847,161 @@ dh(Config) when is_list(Config) ->
exit(Pid, kill)
end.
+srp3(doc) ->
+ ["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp3(suite) -> [];
+srp3(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '3',
+ Scrambler = hexstr2bin("02E2476A"),
+
+ %% X = hexstr2bin("96E54AB0CD4C5123EDCFA4A1502918AAD3C9E2A8"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClientPrivate = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ ServerPrivate = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClientPublic = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ ServerPublic = hexstr2bin("93A8C4D8B7F7395ADCFD4ABA37B015124513D3F37B3E85EB23064BE5"
+ "F53C0AE32FFB9D8C0AA0DCFFA74D632DD67DEBB5C35AAE9812286CC8"
+ "C43CC176ECBC6D3F447594D9554E995B2509127BF88FADDDA4982D03"
+ "8EC3001320712D3B1269308CE70F319B2295FA57674F03A2D993CFB1"
+ "F84C35B7D0C012FA73CD4C8F7D5A71C7"),
+
+ SessionKey = hexstr2bin("C29A986C4D521BBC66428ED11D994CD7431574A6184B83CDCC345092"
+ "791E75748A1D38CAC4BD14760F0D2694B711236419240FF2F172454C"
+ "46ABF4FF39498DAFDD2C82924F7D7BD76CDFCE688C77D93F18A65409"
+ "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),
+
+ {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).
+
+srp6(doc) ->
+ ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp6(suite) -> [];
+srp6(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '6',
+ Scrambler = hexstr2bin("0A2534C0BF52A0DA9001EEC62CF2A546AB0908A7"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClientPrivate = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ ServerPrivate = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClientPublic = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ ServerPublic = hexstr2bin("D2D07845CE7ECDB9845DD36B10ACD3598CC29049DE9F467F84CE16B6"
+ "D97A6DC567AF8B0F9FEDF74962400AD5C357951E64E67B641246F264"
+ "C8DE6D9A72E554D6C8D3194548780A0C438A0FCC509CA88A14AA1DEB"
+ "C0F09E4B37A965D1545DB4AD361346F3189B0EA569C06D326C4E4797"
+ "9E381C748293B7C0591BE0BE419E053E"),
+
+ SessionKey = hexstr2bin("19D22C19612874EBF1F2581F8EFCFDC44C6FDA3B87B0A73823D7E962"
+ "554295D4E48D3A336523ADBDDD0EC8FB0F02687109E97E01C17C93CC"
+ "7216F9CD8A4AC39F0429857D8D1023066614BDFCBCB89F59A0FEB81C"
+ "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),
+
+ {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).
+
+srp6a(doc) ->
+ ["SRP-6a test vectors from RFC5054."];
+srp6a(suite) -> [];
+srp6a(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("BEB25379D1A8581EB5A727673A2441EE"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '6a',
+ Scrambler = hexstr2bin("CE38B9593487DA98554ED47D70A7AE5F462EF019"),
+ Verifier = hexstr2bin("7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D812"
+ "9BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5"
+ "C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5"
+ "EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78"
+ "E955A5E29E7AB245DB2BE315E2099AFB"),
+ ClientPrivate = hexstr2bin("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DD"
+ "DA2D4393"),
+ ServerPrivate = hexstr2bin("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D1"
+ "05284D20"),
+ ClientPublic = hexstr2bin("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4"
+ "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
+ "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
+ "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
+ "B349EF5D76988A3672FAC47B0769447B"),
+ ServerPublic = hexstr2bin("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011"
+ "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99"
+ "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA"
+ "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE"
+ "EB4012B7D7665238A8E3FB004B117B58"),
+
+ SessionKey = hexstr2bin("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D"
+ "233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C"
+ "41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F"
+ "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
+ "C346D7E474B29EDE8A469FFECA686E5A"),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ Verifier = crypto:mod_exp_prime(Generator, UserPassHash, 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).
+
%%
%%
exor_test(doc) ->
@@ -2120,8 +2105,8 @@ worker_loop(N, Config) ->
aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test,
rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test,
hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512,
- hmac_rfc2202, hmac_rfc4231,
- aes_ctr_stream },
+ hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256, hmac_rfc4231_sha384,
+ hmac_rfc4231_sha512, aes_ctr_stream },
F = element(random:uniform(size(Funcs)),Funcs),
%%io:format("worker ~p calling ~p\n",[self(),F]),
@@ -2256,10 +2241,10 @@ openssl_version() ->
undefined
end.
-if_098(Fun) ->
- case openssl_version() of
- V when V < 16#908000 ->
- {skipped,"OpenSSL version too old"};
+if_supported(Algorithm, Fun) ->
+ case proplists:get_bool(Algorithm, crypto:algorithms()) of
+ true ->
+ Fun();
_ ->
- Fun()
+ {skipped, io:format("~s not spupported", [Algorithm])}
end.
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index 86618a4915..ca6b403ac9 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -261,8 +261,8 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
dict:new(), NewFiles),
check_for_duplicate_modules(ModDict);
false ->
- Msg = io_lib:format("Could not scan the following file(s): ~p",
- [lists:flatten(Failed)]),
+ Msg = io_lib:format("Could not scan the following file(s):~n~s",
+ [[Reason || {_Filename, Reason} <- Failed]]),
exit({error, Msg})
end,
{T2, _} = statistics(runtime),
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index eadc42536f..7ea93d480b 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -1162,7 +1162,7 @@ transport.</p>
<marker id="transport_config"/>
<tag><c>{transport_config, term()}</c></tag>
-<tag><c>{transport_config, term(), &dict_Unsigned32;}</c></tag>
+<tag><c>{transport_config, term(), &dict_Unsigned32; | infinity}</c></tag>
<item>
<p>
A term passed as the third argument to the &transport_start; function of
diff --git a/lib/diameter/doc/src/diameter_compile.xml b/lib/diameter/doc/src/diameter_compile.xml
index 0bd7ad1789..fc81e4efed 100644
--- a/lib/diameter/doc/src/diameter_compile.xml
+++ b/lib/diameter/doc/src/diameter_compile.xml
@@ -11,7 +11,7 @@
<comref>
<header>
<copyright>
-<year>2011</year><year>2012</year>
+<year>2011</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -59,6 +59,7 @@ The module &man_make; provides an alternate compilation interface.</p>
Compile a single dictionary file to Erlang source.
Valid options are as follows.</p>
+<taglist>
<tag><![CDATA[-i <dir>]]></tag>
<item>
<p>
@@ -71,7 +72,6 @@ dependency, not an erl/hrl dependency.</p>
Multiple <c>-i</c> options can be specified.</p>
</item>
-<taglist>
<tag><![CDATA[-o <dir>]]></tag>
<item>
<p>
@@ -90,18 +90,30 @@ Supress erl and hrl generation, respectively.</p>
<tag><![CDATA[--prefix <prefix>]]></tag>
<item>
<p>
-Set <c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
-string.
-Overrides any setting in the file itself.</p>
+Transform the input dictionary before compilation, setting
+<c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
+string.</p>
</item>
-<tag><![CDATA[--inherits <dict>]]></tag>
+<tag><![CDATA[--inherits <arg>]]></tag>
<item>
<p>
-Append &dict_inherits; of the specified module.
-Specifying <c>"-"</c> has the effect of discarding clearing any
-previous inherits, both in the dictionary file and on the options
-list.</p>
+Transform the input dictionary before compilation, appending
+<c>&dict_inherits;</c> of the specified string.</p>
+
+<p>
+Two forms of <c>--inherits</c> have special meaning:</p>
+
+<pre>
+--inherits -
+--inherits Prev/Mod
+</pre>
+
+<p>
+The first has the effect of clearing any previous inherits, the second
+of replacing a previous inherits of <c>Prev</c> to one of <c>Mod</c>.
+This allows the semantics of the input dictionary to be changed without
+modifying the file itself.</p>
<p>
Multiple <c>--inherits</c> options can be specified.</p>
diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml
index 1034781ff2..419dc143af 100644
--- a/lib/diameter/doc/src/diameter_dict.xml
+++ b/lib/diameter/doc/src/diameter_dict.xml
@@ -263,15 +263,14 @@ dictionary's definitions but the former makes for easier reuse.</p>
<p>
All dictionaries should typically inherit &the_rfc; AVPs from
-<c>diameter_gen_base_rfc3588</c>.</p>
+<c>diameter_gen_base_rfc6733</c>.</p>
<p>
Example:</p>
<pre>
-@inherits diameter_gen_base_rfc3588
+@inherits diameter_gen_base_rfc6733
</pre>
-
</item>
<marker id="avp_types"/>
diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml
index da6124310e..ec71251be1 100644
--- a/lib/diameter/doc/src/diameter_make.xml
+++ b/lib/diameter/doc/src/diameter_make.xml
@@ -14,6 +14,7 @@
<header>
<copyright>
<year>2012</year>
+<year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -73,7 +74,7 @@ Compile a single dictionary file to Erlang source.
<taglist>
-<tag><c>{include, Dir::string()}</c></tag>
+<tag><c>{include, string()}</c></tag>
<item>
<p>
Prepend the specified directory to the code path.
@@ -85,7 +86,7 @@ dependency, not an erl/hrl dependency.</p>
Multiple <c>include</c> options can be specified.</p>
</item>
-<tag><c>{outdir, Dir::string()}</c></tag>
+<tag><c>{outdir, string()}</c></tag>
<item>
<p>
Write generated source to the specified directory.
@@ -95,18 +96,30 @@ Defaults to the current working directory.</p>
<tag><c>{name|prefix, string()}</c></tag>
<item>
<p>
-Set <c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
-string.
-Overrides any setting in the file itself.</p>
+Transform the input dictionary before compilation, setting
+<c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
+string.</p>
</item>
-<tag><c>{inherits, Mod::string()}</c></tag>
+<tag><c>{inherits, string()}</c></tag>
<item>
<p>
-Append &dict_inherits; of the specified module.
-Specifying <c>"-"</c> has the effect of discarding clearing any
-previous inherits, both in the dictionary file and on the options
-list.</p>
+Transform the input dictionary before compilation, appending
+<c>&dict_inherits;</c> of the specified string.</p>
+
+<p>
+Two forms of <c>@inherits</c> have special meaning:</p>
+
+<pre>
+{inherits, "-"}
+{inherits, "Prev/Mod"}
+</pre>
+
+<p>
+The first has the effect of clearing any previous inherits, the second
+of replacing a previous inherits of <c>Prev</c> to one of <c>Mod</c>.
+This allows the semantics of the input dictionary to be changed without
+modifying the file itself.</p>
<p>
Multiple <c>inherits</c> options can be specified.</p>
@@ -126,8 +139,9 @@ Multiple <c>inherits</c> options can be specified.</p>
<p>
All options are string-valued.
-In particular, it is not currently possible to
-an &dict_inherits; module as an atom() or a path as a &filename;</p>
+In particular, it is not currently possible to specify
+an &dict_inherits; module as an atom(), or a path as an arbitrary
+&filename;</p>
</section>
diff --git a/lib/diameter/examples/code/redirect_cb.erl b/lib/diameter/examples/code/redirect_cb.erl
index da31add70d..69836774a1 100644
--- a/lib/diameter/examples/code/redirect_cb.erl
+++ b/lib/diameter/examples/code/redirect_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-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
@@ -20,7 +20,7 @@
-module(redirect_cb).
-include_lib("diameter/include/diameter.hrl").
--include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl").
+-include_lib("diameter/include/diameter_gen_base_rfc3588.hrl").
%% diameter callbacks
-export([peer_up/3,
diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index 490a1fa8aa..57730cad61 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -335,7 +335,7 @@ call(SvcName, App, Message) ->
-type transport_opt()
:: {transport_module, atom()}
| {transport_config, any()}
- | {transport_config, any(), non_neg_integer() | infinity}
+ | {transport_config, any(), 'Unsigned32'() | infinity}
| {applications, [app_alias()]}
| {capabilities, [capability()]}
| {capabilities_cb, evaluable()}
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 3a2e0d2140..1282930145 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -103,6 +103,10 @@
%% Time to lay low before restarting a dead service.
-define(RESTART_SLEEP, 2000).
+%% Test for a valid timeout.
+-define(IS_UINT32(N),
+ is_integer(N) andalso 0 =< N andalso 0 == N bsr 32).
+
%% A minimal diameter_caps for checking for valid capabilities values.
-define(EXAMPLE_CAPS,
#diameter_caps{origin_host = "TheHost",
@@ -490,13 +494,11 @@ stop(SvcName) ->
%% has many.
add(SvcName, Type, Opts) ->
- %% Ensure usable capabilities. diameter_service:merge_service/2
- %% depends on this.
- lists:foreach(fun(Os) ->
- is_list(Os) orelse ?THROW({capabilities, Os}),
- ok = encode_CER(Os)
- end,
- [Os || {capabilities, Os} <- Opts, is_list(Os)]),
+ %% Ensure acceptable transport options. This won't catch all
+ %% possible errors (faulty callbacks for example) but it catches
+ %% many. diameter_service:merge_service/2 depends on usable
+ %% capabilities for example.
+ ok = transport_opts(Opts),
Ref = make_ref(),
T = {Ref, Type, Opts},
@@ -514,6 +516,61 @@ add(SvcName, Type, Opts) ->
No
end.
+transport_opts(Opts) ->
+ lists:foreach(fun(T) -> opt(T) orelse ?THROW({invalid, T}) end, Opts).
+
+opt({transport_module, M}) ->
+ is_atom(M);
+
+opt({transport_config, _, Tmo}) ->
+ ?IS_UINT32(Tmo) orelse Tmo == infinity;
+
+opt({applications, As}) ->
+ is_list(As);
+
+opt({capabilities, Os}) ->
+ is_list(Os) andalso ok == encode_CER(Os);
+
+opt({capx_timeout, Tmo}) ->
+ ?IS_UINT32(Tmo);
+
+opt({length_errors, T}) ->
+ lists:member(T, [exit, handle, discard]);
+
+opt({reconnect_timer, Tmo}) ->
+ ?IS_UINT32(Tmo);
+
+opt({watchdog_timer, {M,F,A}})
+ when is_atom(M), is_atom(F), is_list(A) ->
+ true;
+opt({watchdog_timer, Tmo}) ->
+ ?IS_UINT32(Tmo);
+
+opt({watchdog_config, L}) ->
+ is_list(L) andalso lists:all(fun wdopt/1, L);
+
+%% Options that we can't validate.
+opt({K, _})
+ when K == transport_config;
+ K == capabilities_cb;
+ K == disconnect_cb;
+ K == private ->
+ true;
+
+%% Anything else, which is ignored by us. This makes options sensitive
+%% to spelling mistakes but arbitrary options are passed by some users
+%% as a way to identify transports. (That is, can't just do away with
+%% it.)
+opt(_) ->
+ true.
+
+wdopt({K,N}) ->
+ (K == okay orelse K == suspect) andalso is_integer(N) andalso 0 =< N;
+wdopt(_) ->
+ false.
+
+%% start_transport/2
+
start_transport(SvcName, T) ->
case diameter_service:start_transport(SvcName, T) of
{ok, _Pid} ->
@@ -636,7 +693,7 @@ opt(K, _) ->
?THROW({value, K}).
sequence({H,N} = T)
- when 0 =< N, N =< 32, 0 =< H, 0 == H bsr N ->
+ when 0 =< N, N =< 32, 0 =< H, 0 == H bsr (32-N) ->
T;
sequence(_) ->
diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl
index 362d593b24..44d81e2778 100644
--- a/lib/diameter/src/base/diameter_lib.erl
+++ b/lib/diameter/src/base/diameter_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-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
@@ -19,77 +19,86 @@
-module(diameter_lib).
--export([report/2, info_report/2,
+-export([info_report/2,
error_report/2,
warning_report/2,
now_diff/1,
time/1,
eval/1,
- ip4address/1,
- ip6address/1,
ipaddr/1,
spawn_opts/2,
wait/1,
fold_tuple/3,
log/4]).
--include("diameter_internal.hrl").
-
%% ---------------------------------------------------------------------------
-%% # info_report(Reason, MFA)
-%%
-%% Input: Reason = Arbitrary term indicating the reason for the report.
-%% MFA = {Module, Function, Args} to report.
-%%
-%% Output: true
+%% # info_report/2
%% ---------------------------------------------------------------------------
-report(Reason, MFA) ->
- info_report(Reason, MFA).
+-spec info_report(Reason :: term(), T :: term())
+ -> true.
-info_report(Reason, MFA) ->
- report(fun error_logger:info_report/1, Reason, MFA),
+info_report(Reason, T) ->
+ report(fun error_logger:info_report/1, Reason, T),
true.
-%%% ---------------------------------------------------------------------------
-%%% # error_report(Reason, MFA)
-%%% # warning_report(Reason, MFA)
-%%%
-%%% Output: false
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # error_report/2
+%% # warning_report/2
+%% ---------------------------------------------------------------------------
+
+-spec error_report(Reason :: term(), T :: term())
+ -> false.
+
+error_report(Reason, T) ->
+ report(fun error_logger:error_report/1, Reason, T).
-error_report(Reason, MFA) ->
- report(fun error_logger:error_report/1, Reason, MFA).
+-spec warning_report(Reason :: term(), T :: term())
+ -> false.
-warning_report(Reason, MFA) ->
- report(fun error_logger:warning_report/1, Reason, MFA).
+warning_report(Reason, T) ->
+ report(fun error_logger:warning_report/1, Reason, T).
-report(Fun, Reason, MFA) ->
- Fun([{why, Reason}, {who, self()}, {what, MFA}]),
+report(Fun, Reason, T) ->
+ Fun([{why, Reason}, {who, self()}, {what, T}]),
false.
-%%% ---------------------------------------------------------------------------
-%%% # now_diff(Time)
-%%%
-%%% Description: Return timer:now_diff(now(), Time) as an {H, M, S, MicroS}
-%%% tuple instead of as integer microseconds.
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # now_diff/1
+%% ---------------------------------------------------------------------------
+
+-spec now_diff(NowT)
+ -> {Hours, Mins, Secs, MicroSecs}
+ when NowT :: {non_neg_integer(), 0..999999, 0..999999},
+ Hours :: non_neg_integer(),
+ Mins :: 0..59,
+ Secs :: 0..59,
+ MicroSecs :: 0..999999.
+
+%% Return timer:now_diff(now(), NowT) as an {H, M, S, MicroS} tuple
+%% instead of as integer microseconds.
now_diff({_,_,_} = Time) ->
- time(timer:now_diff(erlang:now(), Time)).
-
-%%% ---------------------------------------------------------------------------
-%%% # time(Time)
-%%%
-%%% Input: Time = {MegaSec, Sec, MicroSec}
-%%% | MicroSec
-%%%
-%%% Output: {H, M, S, MicroS}
-%%% ---------------------------------------------------------------------------
-
-time({_,_,_} = Time) -> %% time of day
+ time(timer:now_diff(now(), Time)).
+
+%% ---------------------------------------------------------------------------
+%% # time/1
+%%
+%% Return an elapsed time as an {H, M, S, MicroS} tuple.
+%% ---------------------------------------------------------------------------
+
+-spec time(NowT | Diff)
+ -> {Hours, Mins, Secs, MicroSecs}
+ when NowT :: {non_neg_integer(), 0..999999, 0..999999},
+ Diff :: non_neg_integer(),
+ Hours :: non_neg_integer(),
+ Mins :: 0..59,
+ Secs :: 0..59,
+ MicroSecs :: 0..999999.
+
+time({_,_,_} = NowT) -> %% time of day
%% 24 hours = 24*60*60*1000000 = 86400000000 microsec
- time(timer:now_diff(Time, {0,0,0}) rem 86400000000);
+ time(timer:now_diff(NowT, {0,0,0}) rem 86400000000);
time(Micro) -> %% elapsed time
Seconds = Micro div 1000000,
@@ -98,9 +107,21 @@ time(Micro) -> %% elapsed time
S = Seconds rem 60,
{H, M, S, Micro rem 1000000}.
-%%% ---------------------------------------------------------------------------
-%%% # eval(Func)
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # eval/1
+%%
+%% Evaluate a function in various forms.
+%% ---------------------------------------------------------------------------
+
+-type f() :: {module(), atom(), list()}
+ | nonempty_maybe_improper_list(fun(), list())
+ | fun().
+
+-spec eval(Fun)
+ -> term()
+ when Fun :: f()
+ | {f()}
+ | nonempty_maybe_improper_list(f(), list()).
eval({M,F,A}) ->
apply(M,F,A);
@@ -120,66 +141,15 @@ eval({F}) ->
eval(F) ->
F().
-%%% ---------------------------------------------------------------------------
-%%% # ip4address(Addr)
-%%%
-%%% Input: string() (eg. "10.0.0.1")
-%%% | list of integer()
-%%% | tuple of integer()
-%%%
-%%% Output: {_,_,_,_} of integer
-%%%
-%%% Exceptions: error: {invalid_address, Addr, erlang:get_stacktrace()}
-%%% ---------------------------------------------------------------------------
-
-ip4address([_,_,_,_] = Addr) -> %% Length 4 string can't be an address.
- ipaddr(list_to_tuple(Addr));
-
-%% Be brutal.
-ip4address(Addr) ->
- try
- {_,_,_,_} = ipaddr(Addr)
- catch
- error: _ ->
- erlang:error({invalid_address, Addr, ?STACK})
- end.
-
-%%% ---------------------------------------------------------------------------
-%%% # ip6address(Addr)
-%%%
-%%% Input: string() (eg. "1080::8:800:200C:417A")
-%%% | list of integer()
-%%% | tuple of integer()
-%%%
-%%% Output: {_,_,_,_,_,_,_,_} of integer
-%%%
-%%% Exceptions: error: {invalid_address, Addr, erlang:get_stacktrace()}
-%%% ---------------------------------------------------------------------------
-
-ip6address([_,_,_,_,_,_,_,_] = Addr) -> %% Length 8 string can't be an address.
- ipaddr(list_to_tuple(Addr));
-
-%% Be brutal.
-ip6address(Addr) ->
- try
- {_,_,_,_,_,_,_,_} = ipaddr(Addr)
- catch
- error: _ ->
- erlang:error({invalid_address, Addr, ?STACK})
- end.
-
-%%% ---------------------------------------------------------------------------
-%%% # ipaddr(Addr)
-%%%
-%%% Input: string() | tuple of integer()
-%%%
-%%% Output: {_,_,_,_} | {_,_,_,_,_,_,_,_}
-%%%
-%%% Exceptions: error: {invalid_address, erlang:get_stacktrace()}
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # ipaddr/1
+%%
+%% Parse an IP address.
+%% ---------------------------------------------------------------------------
--spec ipaddr(string() | tuple())
- -> inet:ip_address().
+-spec ipaddr([byte()] | tuple())
+ -> inet:ip_address()
+ | none().
%% Don't convert lists of integers since a length 8 list like
%% [$1,$0,$.,$0,$.,$0,$.,$1] is ambiguous: is it "10.0.0.1" or
@@ -193,7 +163,7 @@ ipaddr(Addr) ->
ip(Addr)
catch
error: _ ->
- erlang:error({invalid_address, ?STACK})
+ erlang:error({invalid_address, erlang:get_stacktrace()})
end.
%% Already a tuple: ensure non-negative integers of the right size.
@@ -210,11 +180,12 @@ ip(Addr) ->
{ok, A} = inet_parse:address(Addr), %% documented in inet(3)
A.
-%%% ---------------------------------------------------------------------------
-%%% # spawn_opts(Type, Opts)
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # spawn_opts/2
+%% ---------------------------------------------------------------------------
-%% TODO: config variables.
+-spec spawn_opts(server|worker, list())
+ -> list().
spawn_opts(server, Opts) ->
opts(75000, Opts);
@@ -224,24 +195,32 @@ spawn_opts(worker, Opts) ->
opts(HeapSize, Opts) ->
[{min_heap_size, HeapSize} | lists:keydelete(min_heap_size, 1, Opts)].
-%%% ---------------------------------------------------------------------------
-%%% # wait(MRefs)
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # wait/1
+%% ---------------------------------------------------------------------------
+
+-spec wait([pid()])
+ -> ok.
wait(L) ->
- w([erlang:monitor(process, P) || P <- L]).
+ down([erlang:monitor(process, P) || P <- L]).
-w([]) ->
+down([]) ->
ok;
-w(L) ->
- receive
- {'DOWN', MRef, process, _, _} ->
- w(lists:delete(MRef, L))
- end.
+down([MRef|T]) ->
+ receive {'DOWN', MRef, process, _, _} -> ok end,
+ down(T).
-%%% ---------------------------------------------------------------------------
-%%% # fold_tuple(N, T0, T)
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # fold_tuple/3
+%% ---------------------------------------------------------------------------
+
+-spec fold_tuple(N, T0, T)
+ -> tuple()
+ when N :: pos_integer(),
+ T0 :: tuple(),
+ T :: tuple()
+ | undefined.
%% Replace fields in T0 by those of T starting at index N, unless the
%% new value is 'undefined'.
@@ -262,11 +241,11 @@ ft(undefined, {_, T}) ->
ft(Value, {Idx, T}) ->
setelement(Idx, T, Value).
-%%% ----------------------------------------------------------
-%%% # log(Slogan, Mod, Line, Details)
-%%%
-%%% Called to have something to trace on for happenings of interest.
-%%% ----------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # log/4
+%%
+%% Called to have something to trace on for happenings of interest.
+%% ---------------------------------------------------------------------------
-log(_, _, _, _) ->
+log(_Slogan, _Mod, _Line, _Details) ->
ok.
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index 66342f7b62..bee3e507fd 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -198,6 +198,7 @@ i({Ack, WPid, {M, Ref} = T, Opts, {Mask,
OnLengthErr = proplists:get_value(length_errors, Opts, exit),
lists:member(OnLengthErr, [exit, handle, discard])
orelse ?ERROR({invalid, {length_errors, OnLengthErr}}),
+ %% Error checking is for configuration added in old code.
{TPid, Addrs} = start_transport(T, Rest, Svc),
@@ -212,9 +213,6 @@ i({Ack, WPid, {M, Ref} = T, Opts, {Mask,
%% transports on the same service can use different local addresses.
%% The local addresses are put into Host-IP-Address avps here when
%% sending capabilities exchange messages.
-%%
-%% Invalid transport config may cause us to crash but note that the
-%% watchdog start (start/2) succeeds regardless.
%% Wait for the caller to have a monitor to avoid a race with our
%% death. (Since the exit reason is used in diameter_service.)
@@ -846,8 +844,12 @@ a('DPR', #diameter_caps{origin_host = {Host, _},
%% recv_CER/2
recv_CER(CER, #state{service = Svc, dictionary = Dict}) ->
- {ok, T} = diameter_capx:recv_CER(CER, Svc, Dict),
- T.
+ case diameter_capx:recv_CER(CER, Svc, Dict) of
+ {ok, T} ->
+ T;
+ {error, Reason} ->
+ close({'CER', CER, Svc, Dict, Reason})
+ end.
%% handle_CEA/1
@@ -907,8 +909,12 @@ recv_CEA(#diameter_packet{header = #diameter_header{version
errors = []},
#state{service = Svc,
dictionary = Dict}) ->
- {ok, T} = diameter_capx:recv_CEA(CEA, Svc, Dict),
- T;
+ case diameter_capx:recv_CEA(CEA, Svc, Dict) of
+ {ok, T} ->
+ T;
+ {error, Reason} ->
+ close({'CEA', CEA, Svc, Dict, Reason})
+ end;
recv_CEA(Pkt, S) ->
close({'CEA', caps(S), Pkt}).
@@ -987,8 +993,17 @@ capz(#diameter_caps{} = L, #diameter_caps{} = R) ->
%% close/1
close(Reason) ->
+ report(Reason),
throw({?MODULE, close, Reason}).
+%% Could possibly log more here.
+report({M, _, _, _, _} = T)
+ when M == 'CER';
+ M == 'CEA' ->
+ diameter_lib:error_report(failure, T);
+report(_) ->
+ ok.
+
%% dwa/1
dwa(#diameter_caps{origin_host = OH,
diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index 82ca603cf3..41c493ff20 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -158,7 +158,7 @@ wait(Ref, Pid) ->
config(Opts) ->
Config = proplists:get_value(watchdog_config, Opts, []),
is_list(Config) orelse config_error({watchdog_config, Config}),
- lists:foldl(fun config/2, #config{}, Config).
+ lists:foldl(fun config/2, #config{}, Config). %% ^ added in old code
config({suspect, N}, Rec)
when ?IS_NATURAL(N) ->
@@ -168,7 +168,7 @@ config({okay, N}, Rec)
when ?IS_NATURAL(N) ->
Rec#config{okay = N};
-config(T, _) ->
+config(T, _) -> %% added in old code
config_error(T).
%% start/5
@@ -225,7 +225,8 @@ dict0(_, _, Acc) ->
Acc.
config_error(T) ->
- ?ERROR({configuration_error, T}).
+ diameter_lib:error_report(configuration_error, T),
+ exit({shutdown, {configuration_error, T}}).
%% handle_call/3
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index 061f0bcbef..9719c67b32 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -93,6 +93,11 @@ info:
@$(call list,HRL_FILES)
@echo
@$(call list,SUITES)
+ @echo
+ @echo erl = $(shell which erl)
+ @erl -noinput \
+ -eval 'io:format("diameter = ~s~n", [code:lib_dir(diameter)])' \
+ -s init stop
@echo ========================================
help:
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index dc8cbffc83..0baac59c1a 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -65,7 +65,7 @@ lib(N, {_,_} = T) ->
lib(IP, B) ->
LA = tuple_to_list(IP),
{SA,Fun} = ip(LA),
- [] = run([[fun lib/4, IP, B, Fun, A] || A <- [IP, LA, SA]]).
+ [] = run([[fun lib/4, IP, B, Fun, A] || A <- [IP, SA]]).
lib(IP, B, Fun, A) ->
try Fun(A) of
@@ -78,10 +78,10 @@ lib(IP, B, Fun, A) ->
ip([_,_,_,_] = A) ->
[$.|S] = lists:append(["." ++ integer_to_list(N) || N <- A]),
- {S, fun diameter_lib:ip4address/1};
+ {S, fun diameter_lib:ipaddr/1};
ip([_,_,_,_,_,_,_,_] = A) ->
[$:|S] = lists:flatten([":" ++ io_lib:format("~.16B", [N]) || N <- A]),
- {S, fun diameter_lib:ip6address/1}.
+ {S, fun diameter_lib:ipaddr/1}.
%% ------------------------------------------------------------------------
%% base/1
diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl
index 79bf9d32db..81722c8dca 100644
--- a/lib/diameter/test/diameter_compiler_SUITE.erl
+++ b/lib/diameter/test/diameter_compiler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-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
@@ -31,8 +31,7 @@
%% testcases
-export([format/1, format/2,
replace/1, replace/2,
- generate/1, generate/4,
- examples/1]).
+ generate/1, generate/4]).
-export([dict/0]). %% fake dictionary module
@@ -328,14 +327,6 @@
"@codecs mymod "
"Origin-Host Origin-Realm\n&"}]}]).
-%% Standard dictionaries in examples/dict.
--define(EXAMPLES, [rfc4004_mip,
- rfc4005_nas,
- rfc4006_cc,
- rfc4072_eap,
- rfc4590_digest,
- rfc4740_sip]).
-
%% ===========================================================================
suite() ->
@@ -344,8 +335,7 @@ suite() ->
all() ->
[format,
replace,
- generate,
- examples].
+ generate].
%% Error handling testcases will make an erroneous dictionary out of
%% the base dictionary and check that the expected error results.
@@ -429,41 +419,6 @@ generate(Mods, Bin, N, Mode) ->
andalso ({ok, _} = compile:file(File ++ ".erl", [return_errors])).
%% ===========================================================================
-%% examples/1
-%%
-%% Compile dictionaries extracted from various standards.
-
-examples(_Config) ->
- Dir = filename:join([code:lib_dir(diameter, examples), "dict"]),
- [D || D <- ?EXAMPLES, _ <- [examples(?S(D), Dir)]].
-
-examples(Dict, Dir) ->
- {Name, Pre} = make_name(Dict),
- ok = diameter_make:codec(filename:join([Dir, Dict ++ ".dia"]),
- [{name, Name},
- {prefix, Pre},
- inherits("rfc3588_base")
- | opts(Dict)]),
- {ok, _, _} = compile:file(Name ++ ".erl", [return]).
-
-opts(M)
- when M == "rfc4006_cc";
- M == "rfc4072_eap" ->
- [inherits("rfc4005_nas")];
-opts("rfc4740_sip") ->
- [inherits("rfc4590_digest")];
-opts(_) ->
- [].
-
-inherits(File) ->
- {Name, _} = make_name(File),
- {inherits, File ++ "/" ++ Name}.
-
-make_name(File) ->
- {R, [$_|N]} = lists:splitwith(fun(C) -> C /= $_ end, File),
- {string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}.
-
-%% ===========================================================================
modify(Bin, Mods) ->
lists:foldl(fun re/2, Bin, Mods).
diff --git a/lib/diameter/test/diameter_config_SUITE.erl b/lib/diameter/test/diameter_config_SUITE.erl
new file mode 100644
index 0000000000..47def9c8c9
--- /dev/null
+++ b/lib/diameter/test/diameter_config_SUITE.erl
@@ -0,0 +1,261 @@
+%% coding: utf-8
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Test service and transport config. In particular, of the detection
+%% of config errors.
+%%
+
+-module(diameter_config_SUITE).
+
+-export([suite/0,
+ all/0]).
+
+%% testcases
+-export([start/1,
+ start_service/1,
+ add_transport/1,
+ stop/1]).
+
+-define(util, diameter_util).
+
+%% Lists of {Key, GoodConfigList, BadConfigList} with which to
+%% configure.
+
+-define(SERVICE_CONFIG,
+ [{application,
+ [[[{dictionary, diameter_gen_base_rfc6733},
+ {module, ?MODULE}]]
+ | [[[{dictionary, D},
+ {module, M},
+ {alias, A},
+ {state, S},
+ {answer_errors, AE},
+ {request_errors, RE},
+ {call_mutates_state, C}]]
+ || D <- [diameter_gen_base_rfc3588, diameter_gen_base_rfc6733],
+ M <- [?MODULE, [?MODULE, now()]],
+ A <- [0, common, make_ref()],
+ S <- [[], make_ref()],
+ AE <- [report, callback, discard],
+ RE <- [answer_3xxx, answer, callback],
+ C <- [true, false]]],
+ [[x],
+ [[]],
+ [[{dictionary, diameter_gen_base_rfc3588}]],
+ [[{module, ?MODULE}]]
+ | [[[{dictionary, diameter_gen_base_rfc6733},
+ {module, ?MODULE},
+ {K,x}]]
+ || K <- [answer_errors,
+ request_errors,
+ call_mutates_state]]]},
+ {restrict_connections,
+ [[false], [node], [nodes], [[node(), node()]]],
+ []},
+ {sequence,
+ [[{0,32}], [{1,31}]],
+ [[{2,31}]]},
+ {share_peers,
+ [[true],
+ [false],
+ [[node()]]],
+ [[x]]},
+ {use_shared_peers,
+ [[true],
+ [false],
+ [[node(), node()]]],
+ [[x]]}]).
+
+-define(TRANSPORT_CONFIG,
+ [{transport_module,
+ [[?MODULE]],
+ [[[?MODULE]]]},
+ {transport_config,
+ [[{}, 3000],
+ [{}, infinity]],
+ [[{}, x]]},
+ {applications,
+ [[[1, a, [x]]]],
+ [[x]]},
+ {capabilities,
+ [[[{'Origin-Host', "diameter.erlang.org"}]],
+ [[{'Origin-Realm', "erlang.org"}]]]
+ ++ [[[{'Host-IP-Address', L}]]
+ || L <- [[{127,0,0,1}],
+ ["127.0.0.1"],
+ ["127.0.0.1", "FFFF::1", "::1", {1,2,3,4,5,6,7,8}]]]
+ ++ [[[{'Product-Name', N}]]
+ || N <- [["Product", $-, ["Name"]],
+ "Norðurálfa",
+ "ᚠᚢᚦᚨᚱᚲ"]]
+ ++ [[[{K,V}]]
+ || K <- ['Vendor-Id',
+ 'Origin-State-Id',
+ 'Firmware-Revision'],
+ V <- [0, 256, 16#FFFF]]
+ ++ [[[{K,V}]]
+ || K <- ['Supported-Vendor-Id',
+ 'Auth-Application-Id',
+ 'Acct-Application-Id',
+ 'Inband-Security-Id'],
+ V <- [[17], [0, 256, 16#FFFF]]]
+ ++ [[[{'Vendor-Specific-Application-Id',
+ [[{'Vendor-Id', V},
+ {'Auth-Application-Id', [0]},
+ {'Acct-Application-Id', [4]}]]}]]
+ || V <- [1, [1]]],
+ [[x], [[{'Origin-Host', "ᚠᚢᚦᚨᚱᚲ"}]]]
+ ++ [[[{'Host-IP-Address', A}]]
+ || A <- [{127,0,0,1}]]
+ ++ [[[{'Product-Name', N}]]
+ || N <- [x, 1]]
+ ++ [[[{K,V}]]
+ || K <- ['Vendor-Id',
+ 'Origin-State-Id',
+ 'Firmware-Revision'],
+ V <- [x, [0], -1, 1 bsl 32]]
+ ++ [[[{K,V}]]
+ || K <- ['Supported-Vendor-Id',
+ 'Auth-Application-Id',
+ 'Acct-Application-Id',
+ 'Inband-Security-Id'],
+ V <- [x, 17, [-1], [1 bsl 32]]]
+ ++ [[[{'Vendor-Specific-Application-Id', V}]]
+ || V <- [x,
+ [[{'Vendor-Id', 1 bsl 32}]],
+ [[{'Auth-Application-Id', 1}]]]]},
+ {capabilities_cb,
+ [[x]],
+ []},
+ {capx_timeout,
+ [[3000]],
+ [[{?MODULE, tmo, []}]]},
+ {disconnect_cb,
+ [[x]],
+ []},
+ {length_errors,
+ [[exit], [handle], [discard]],
+ [[x]]},
+ {reconnect_timer,
+ [[3000]],
+ [[infinity]]},
+ {watchdog_timer,
+ [[3000],
+ [{?MODULE, tmo, []}]],
+ [[infinity],
+ [-1]]},
+ {watchdog_config,
+ [[[{okay, 0}, {suspect, 0}]],
+ [[{okay, 1}]],
+ [[{suspect, 2}]]],
+ [[x],
+ [[{open, 0}]]]}]).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 60}}].
+
+all() ->
+ [start,
+ start_service,
+ add_transport,
+ stop].
+
+%% ===========================================================================
+
+start(_) ->
+ ok = diameter:start().
+
+start_service(T)
+ when is_tuple(T) ->
+ do(fun start/3, T);
+
+start_service(_) ->
+ [] = ?util:run([{?MODULE, start_service, [T]}
+ || T <- [lists:keyfind(capabilities, 1, ?TRANSPORT_CONFIG)
+ | ?SERVICE_CONFIG]]).
+
+add_transport(T)
+ when is_tuple(T) ->
+ do(fun add/3, T);
+
+add_transport(_) ->
+ [] = ?util:run([{?MODULE, add_transport, [T]}
+ || T <- ?TRANSPORT_CONFIG]).
+
+stop(_) ->
+ ok = diameter:stop().
+
+%% ===========================================================================
+
+%% do/2
+
+do(F, {Key, Good, Bad}) ->
+ F(Key, Good, Bad).
+
+%% add/3
+
+add(Key, Good, Bad) ->
+ {[],[]} = {[{Vs,T} || Vs <- Good,
+ T <- [add(Key, Vs)],
+ [T] /= [T || {ok,_} <- [T]]],
+ [{Vs,T} || Vs <- Bad,
+ T <- [add(Key, Vs)],
+ [T] /= [T || {error,_} <- [T]]]}.
+
+add(Key, Vs) ->
+ T = list_to_tuple([Key | Vs]),
+ diameter:add_transport(make_ref(), {connect, [T]}).
+
+%% start/3
+
+start(Key, Good, Bad) ->
+ {[],[]} = {[{Vs,T} || Vs <- Good,
+ T <- [start(Key, Vs)],
+ T /= ok],
+ [{Vs,T} || Vs <- Bad,
+ T <- [start(Key, Vs)],
+ [T] /= [T || {error,_} <- [T]]]}.
+
+start(capabilities = K, [Vs]) ->
+ if is_list(Vs) ->
+ start(make_ref(), Vs ++ apps(K));
+ true ->
+ {error, Vs}
+ end;
+
+start(Key, Vs)
+ when is_atom(Key) ->
+ start(make_ref(), [list_to_tuple([Key | Vs]) | apps(Key)]);
+
+start(SvcName, Opts) ->
+ try
+ diameter:start_service(SvcName, Opts)
+ after
+ diameter:stop_service(SvcName)
+ end.
+
+apps(application) ->
+ [];
+apps(_) ->
+ [{application, [{dictionary, diameter_gen_base_rfc6733},
+ {module, ?MODULE}]}].
diff --git a/lib/diameter/test/diameter_ct.erl b/lib/diameter/test/diameter_ct.erl
index 1697287a22..ed2f884681 100644
--- a/lib/diameter/test/diameter_ct.erl
+++ b/lib/diameter/test/diameter_ct.erl
@@ -53,7 +53,7 @@ info(L0, L1) ->
L0,
L1),
Diff = [T, C, {memory, M}],
- ct:pal("INFO: ~p~n", [Diff]).
+ io:format("INFO: ~p~n", [Diff]).
diff(time, T0, T1) ->
timer:now_diff(T1, T0);
diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl
new file mode 100644
index 0000000000..6d797f6911
--- /dev/null
+++ b/lib/diameter/test/diameter_examples_SUITE.erl
@@ -0,0 +1,334 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Test example code under ../examples/code.
+%%
+
+-module(diameter_examples_SUITE).
+
+-export([suite/0,
+ all/0]).
+
+%% testcases
+-export([dict/1, dict/0,
+ code/1,
+ enslave/1,
+ start/1,
+ traffic/1,
+ stop/1]).
+
+-export([install/1,
+ call/1]).
+
+-include("diameter.hrl").
+
+%% ===========================================================================
+
+-define(util, diameter_util).
+
+%% The order here is significant and causes the server to listen
+%% before the clients connect.
+-define(NODES, [compile, server, client]).
+
+%% Options to ct_slave:start/2.
+-define(TIMEOUTS, [{T, 15000} || T <- [boot_timeout,
+ init_timeout,
+ start_timeout]]).
+
+%% @inherits dependencies between example dictionaries. This is needed
+%% in order compile them in the right order. Can't compile to erl to
+%% find out since @inherits is a beam dependency.
+-define(INHERITS, [{rfc4006_cc, [rfc4005_nas]},
+ {rfc4072_eap, [rfc4005_nas]},
+ {rfc4740_sip, [rfc4590_digest]}]).
+
+%% Common dictionaries to inherit from examples.
+-define(DICT0, [rfc3588_base, rfc6733_base]).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 45}}].
+
+all() ->
+ [dict,
+ code,
+ enslave,
+ start,
+ traffic,
+ stop].
+
+%% ===========================================================================
+%% dict/1
+%%
+%% Compile example dictionaries in examples/dict.
+
+dict() ->
+ [{timetrap, {minutes, 10}}].
+
+dict(_Config) ->
+ Dirs = [filename:join(H ++ ["examples", "dict"])
+ || H <- [[code:lib_dir(diameter)], [here(), ".."]]],
+ [] = [{F,D,RC} || {_,F} <- sort(find_files(Dirs, ".*\\.dia")),
+ D <- ?DICT0,
+ RC <- [make(F,D)],
+ RC /= ok].
+
+sort([{_,_} | _] = Files) ->
+ lists:sort(fun({A,_},{B,_}) ->
+ sort([filename:rootname(F) || F <- [A,B]])
+ end,
+ Files);
+
+sort([A,B] = L) ->
+ [DA,DB] = [dep([D],[]) || D <- L],
+ case {[A] -- DB, [B] -- DA} of
+ {[], [_]} -> %% B depends on A
+ true;
+ {[_], []} -> %% A depends on B
+ false;
+ {[_],[_]} -> %% or not
+ length(DA) < length(DB)
+ end.
+
+%% Recursively accumulate inherited dictionaries.
+dep([D|Rest], Acc) ->
+ dep(dep(D), Rest, Acc);
+dep([], Acc) ->
+ Acc.
+
+dep([{Dict, _} | T], Rest, Acc) ->
+ dep(T, [Dict | Rest], [Dict | Acc]);
+dep([], Rest, Acc) ->
+ dep(Rest, Acc).
+
+make(Path, Dict0)
+ when is_atom(Dict0) ->
+ make(Path, atom_to_list(Dict0));
+
+make(Path, Dict0) ->
+ Dict = filename:rootname(filename:basename(Path)),
+ {Mod, Pre} = make_name(Dict),
+ {"diameter_gen_base" ++ Suf = Mod0, _} = make_name(Dict0),
+ Name = Mod ++ Suf,
+ try
+ ok = to_erl(Path, [{name, Name},
+ {prefix, Pre},
+ {inherits, "rfc3588_base/" ++ Mod0}
+ | [{inherits, D ++ "/" ++ M ++ Suf}
+ || {D,M} <- dep(Dict)]]),
+ ok = to_beam(Name)
+ catch
+ throw: {_,_} = E ->
+ E
+ end.
+
+to_erl(File, Opts) ->
+ case diameter_make:codec(File, Opts) of
+ ok ->
+ ok;
+ No ->
+ throw({make, No})
+ end.
+
+to_beam(Name) ->
+ case compile:file(Name ++ ".erl", [return]) of
+ {ok, _, _} ->
+ ok;
+ No ->
+ throw({compile, No})
+ end.
+
+dep(Dict) ->
+ case lists:keyfind(list_to_atom(Dict), 1, ?INHERITS) of
+ {_, Is} ->
+ lists:map(fun inherits/1, Is);
+ false ->
+ []
+ end.
+
+inherits(Dict)
+ when is_atom(Dict) ->
+ inherits(atom_to_list(Dict));
+
+inherits(Dict) ->
+ {Name, _} = make_name(Dict),
+ {Dict, Name}.
+
+make_name(Dict) ->
+ {R, [$_|N]} = lists:splitwith(fun(C) -> C /= $_ end, Dict),
+ {string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}.
+
+%% ===========================================================================
+%% code/1
+%%
+%% Compile example code under examples/code.
+
+code(Config) ->
+ Node = slave(hd(?NODES), here()),
+ [] = rpc:call(Node,
+ ?MODULE,
+ install,
+ [proplists:get_value(priv_dir, Config)]).
+
+%% Compile on another node since the code path may be modified.
+install(PrivDir) ->
+ Top = install(here(), PrivDir),
+ Src = filename:join([Top, "examples", "code"]),
+ Files = find_files([Src], ".*\\.erl"),
+ [] = [{F,E} || {_,F} <- Files,
+ {error, _, _} = E <- [compile:file(F, [warnings_as_errors,
+ return_errors])]].
+
+%% Copy include files into a temporary directory and adjust the code
+%% path in order for example code to be able to include them with
+%% include_lib. This is really only required when running in the reop
+%% since generated includes, that the example code wants to
+%% include_lib, are under src/gen and there's no way to get get the
+%% preprocessor to find these otherwise. Generated hrls are only be
+%% under include in an installation. ("Installing" them locally is
+%% anathema.)
+install(Dir, PrivDir) ->
+ %% Remove the path added by slave/1 (needed for the rpc:call/4 in
+ %% compile/1 to find ?MODULE) so the call to code:lib_dir/2 below
+ %% returns the installed path.
+ [Ebin | _] = code:get_path(),
+ true = code:del_path(Ebin),
+ Top = top(Dir, code:lib_dir(diameter)),
+
+ %% Create a new diameter/include in priv_dir. Copy all includes
+ %% there, from below ../include and ../src/gen if they exist (in
+ %% the repo).
+ Tmp = filename:join([PrivDir, "diameter"]),
+ TmpInc = filename:join([PrivDir, "diameter", "include"]),
+ TmpEbin = filename:join([PrivDir, "diameter", "ebin"]),
+ [] = [{T,E} || T <- [Tmp, TmpInc, TmpEbin],
+ {error, E} <- [file:make_dir(T)]],
+
+ Inc = filename:join([Top, "include"]),
+ Gen = filename:join([Top, "src", "gen"]),
+ Files = find_files([Inc, Gen], ".*\\.hrl"),
+ [] = [{F,E} || {_,F} <- Files,
+ B <- [filename:basename(F)],
+ D <- [filename:join([TmpInc, B])],
+ {error, E} <- [file:copy(F,D)]],
+
+ %% Prepend the created directory just so that code:lib_dir/1 finds
+ %% it when compile:file/2 tries to resolve include_lib.
+ true = code:add_patha(TmpEbin),
+ Tmp = code:lib_dir(diameter), %% assert
+ %% Return the top directory containing examples/code.
+ Top.
+
+find_files(Dirs, RE) ->
+ lists:foldl(fun(D,A) -> fold_files(D, RE, A) end,
+ orddict:new(),
+ Dirs).
+
+fold_files(Dir, RE, Acc) ->
+ filelib:fold_files(Dir, RE, false, fun store/2, Acc).
+
+store(Path, Dict) ->
+ orddict:store(filename:basename(Path), Path, Dict).
+
+%% ===========================================================================
+
+%% enslave/1
+%%
+%% Start two nodes: one for the server, one for the client.
+
+enslave(Config) ->
+ Dir = here(),
+ Nodes = [{N, slave(N, Dir)} || N <- tl(?NODES)],
+ ?util:write_priv(Config, nodes, Nodes).
+
+slave(Name, Dir) ->
+ {ok, Node} = ct_slave:start(Name, ?TIMEOUTS),
+ ok = rpc:call(Node,
+ code,
+ add_pathsa,
+ [[Dir, filename:join([Dir, "..", "ebin"])]]),
+ Node.
+
+here() ->
+ filename:dirname(code:which(?MODULE)).
+
+top(Dir, LibDir) ->
+ File = filename:join([Dir, "depend.sed"]), %% only in the repo
+ case filelib:is_regular(File) of
+ true -> filename:join([Dir, ".."]);
+ false -> LibDir
+ end.
+
+%% start/1
+
+start(server) ->
+ ok = diameter:start(),
+ ok = server:start(),
+ {ok, Ref} = server:listen(tcp),
+ [_] = ?util:lport(tcp, Ref, 20),
+ ok;
+
+start(client) ->
+ ok = diameter:start(),
+ true = diameter:subscribe(client),
+ ok = client:start(),
+ {ok, Ref} = client:connect(tcp),
+ receive #diameter_event{info = {up, Ref, _, _, _}} -> ok end;
+
+start(Config) ->
+ Nodes = ?util:read_priv(Config, nodes),
+ [] = [RC || {T,N} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, start, [T])],
+ RC /= ok].
+
+%% traffic/1
+%%
+%% Send successful messages from client to server.
+
+traffic(server) ->
+ ok;
+
+traffic(client) ->
+ {_, MRef} = spawn_monitor(fun() -> call(100) end),
+ receive {'DOWN', MRef, process, _, Reason} -> Reason end;
+
+traffic(Config) ->
+ Nodes = ?util:read_priv(Config, nodes),
+ [] = [RC || {T,N} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, traffic, [T])],
+ RC /= ok].
+
+call(0) ->
+ exit(ok);
+
+call(N) ->
+ {ok, _} = client:call(),
+ call(N-1).
+
+%% stop/1
+
+stop(Name)
+ when is_atom(Name) ->
+ {ok, _Node} = ct_slave:stop(Name),
+ ok;
+
+stop(_Config) ->
+ [] = [RC || N <- ?NODES, RC <- [stop(N)], RC /= ok].
diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk
index beff588a02..1a829f8031 100644
--- a/lib/diameter/test/modules.mk
+++ b/lib/diameter/test/modules.mk
@@ -29,11 +29,13 @@ MODULES = \
diameter_capx_SUITE \
diameter_codec_SUITE \
diameter_codec_test \
+ diameter_config_SUITE \
diameter_compiler_SUITE \
diameter_dict_SUITE \
diameter_distribution_SUITE \
diameter_dpr_SUITE \
diameter_event_SUITE \
+ diameter_examples_SUITE \
diameter_failover_SUITE \
diameter_gen_sctp_SUITE \
diameter_length_SUITE \
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 0a2c6e822f..42c7e360c1 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -1053,6 +1053,8 @@ type(hipe_bifs, mark_referred_from, 1, Xs) ->
fun (_) -> t_nil() end);
type(hipe_bifs, merge_term, 1, Xs) ->
strict(arg_types(hipe_bifs, merge_term, 1), Xs, fun ([X]) -> X end);
+type(hipe_bifs, nstack_used_size, 0, _) ->
+ t_non_neg_fixnum();
type(hipe_bifs, patch_call, 3, Xs) ->
strict(arg_types(hipe_bifs, patch_call, 3), Xs, fun (_) -> t_nil() end);
type(hipe_bifs, patch_insn, 3, Xs) ->
@@ -2361,6 +2363,8 @@ arg_types(hipe_bifs, mark_referred_from, 1) ->
[t_mfa()];
arg_types(hipe_bifs, merge_term, 1) ->
[t_any()];
+arg_types(hipe_bifs, nstack_used_size, 0) ->
+ [];
arg_types(hipe_bifs, patch_call, 3) ->
[t_integer(), t_integer(), t_trampoline()];
arg_types(hipe_bifs, patch_insn, 3) ->
diff --git a/lib/hipe/icode/Makefile b/lib/hipe/icode/Makefile
index 0f2d6db39b..238f70cf59 100644
--- a/lib/hipe/icode/Makefile
+++ b/lib/hipe/icode/Makefile
@@ -83,7 +83,7 @@ DOC_FILES= $(DOC_MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec # +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_unused_import +warn_exported_vars +warn_missing_spec # +warn_untyped_record
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/icode/hipe_icode.erl b/lib/hipe/icode/hipe_icode.erl
index 3e211bf385..dfea092af2 100644
--- a/lib/hipe/icode/hipe_icode.erl
+++ b/lib/hipe/icode/hipe_icode.erl
@@ -261,7 +261,6 @@
%% {tuple, N}
%% atom
%% {atom, Atom}
-%% constant
%% number
%% integer
%% {integer, N}
@@ -380,7 +379,6 @@
%% | {tuple, integer()}
%% | atom
%% | {atom, atom()}
-%% | constant
%% | number
%% | integer
%% | {integer, integer()}
diff --git a/lib/hipe/icode/hipe_icode.hrl b/lib/hipe/icode/hipe_icode.hrl
index d76eebf78d..89d297ef01 100644
--- a/lib/hipe/icode/hipe_icode.hrl
+++ b/lib/hipe/icode/hipe_icode.hrl
@@ -23,12 +23,6 @@
%%=====================================================================
%%---------------------------------------------------------------------
-%% THIS DOES NOT REALLY BELONG HERE -- PLEASE REMOVE ASAP!
-%%---------------------------------------------------------------------
-
--type ordset(T) :: [T].
-
-%%---------------------------------------------------------------------
%% Include files needed for the compilation of this header file
%%---------------------------------------------------------------------
@@ -67,7 +61,7 @@
| 'op_exact_eqeq_2' | 'suspend_msg_timeout'.
-type icode_type_test() :: 'atom' | 'bignum' | 'binary' | 'bitstr' | 'boolean'
- | 'cons' | 'constant' | 'fixnum' | 'float'
+ | 'cons' | 'fixnum' | 'float'
| 'function' | 'function2' | 'integer' | 'list' | 'nil'
| 'number' | 'pid' | 'port' | 'reference' | 'tuple'
| {'atom', atom()} | {'integer', integer()}
diff --git a/lib/hipe/icode/hipe_icode_callgraph.erl b/lib/hipe/icode/hipe_icode_callgraph.erl
index ae4b5785c4..6d004823e2 100644
--- a/lib/hipe/icode/hipe_icode_callgraph.erl
+++ b/lib/hipe/icode/hipe_icode_callgraph.erl
@@ -102,7 +102,7 @@ pp(#icode_callgraph{ordered_sccs = SCCs}) ->
%%------------------------------------------------------------------------
%% Get the modules called from this module
--spec get_called_modules([mfa_icode()]) -> ordset(atom()).
+-spec get_called_modules([mfa_icode()]) -> ordsets:ordset(atom()).
get_called_modules(List) ->
get_remote_calls(List, []).
diff --git a/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl b/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl
index 675c8c1ad8..718d5d442b 100644
--- a/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl
+++ b/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl
@@ -129,8 +129,8 @@ maps_expr_key_enter(Expr, Maps) ->
key = none :: 'none' | tuple(), % illegal_icode_instr()
defs = none :: 'none' | [icode_var()],
direct_replace = false :: boolean(),
- inserts = ?SETS:new() :: ?SET(_),
- use = ?SETS:new() :: ?SET(_)}).
+ inserts = ?SETS:new() :: ?SETS:?SET(_),
+ use = ?SETS:new() :: ?SETS:?SET(_)}).
expr_id(#expr{id = Out}) -> Out.
expr_defs(#expr{defs = Out}) -> Out.
@@ -169,7 +169,7 @@ expr_create(Key, Defs) ->
%% exprid - a expression value number which is the expression that
%% the variable is defined by.
--record(varinfo, {use = ?SETS:new() :: ?SET(_),
+-record(varinfo, {use = ?SETS:new() :: ?SETS:?SET(_),
ref = none :: 'none' | {non_neg_integer(), non_neg_integer()},
elem = none :: 'none' | {icode_var(), non_neg_integer()},
exprid = none :: 'none' | non_neg_integer()}).
@@ -215,12 +215,12 @@ varinfo_use_add(#varinfo{use = UseSet} = I, Use) ->
varmap = [] :: [{icode_var(), icode_var()}],
pre_loop = false :: boolean(),
non_struct_defs = gb_sets:new() :: gb_set(),
- up_expr = none :: 'none' | ?SET(_),
- killed_expr = none :: 'none' | ?SET(_),
- sub_inserts = ?SETS:new() :: ?SET(_),
- inserts = ?SETS:new() :: ?SET(_),
- antic_in = none :: 'none' | ?SET(_),
- antic_out = none :: 'none' | ?SET(_),
+ up_expr = none :: 'none' | ?SETS:?SET(_),
+ killed_expr = none :: 'none' | ?SETS:?SET(_),
+ sub_inserts = ?SETS:new() :: ?SETS:?SET(_),
+ inserts = ?SETS:new() :: ?SETS:?SET(_),
+ antic_in = none :: 'none' | ?SETS:?SET(_),
+ antic_out = none :: 'none' | ?SETS:?SET(_),
struct_type = [] :: [struct_type()],
struct_elems = [] :: [struct_elems()]}).
diff --git a/lib/hipe/regalloc/hipe_ls_regalloc.erl b/lib/hipe/regalloc/hipe_ls_regalloc.erl
index d06b938bea..7fb65be6a0 100644
--- a/lib/hipe/regalloc/hipe_ls_regalloc.erl
+++ b/lib/hipe/regalloc/hipe_ls_regalloc.erl
@@ -72,7 +72,7 @@
%% PhysRegs = [reg()]
%% Entrypoints = [labelname()]
%% DontSpill = reg()
-%% Options = proplist:proplist()
+%% Options = proplists:proplist()
%% Target = atom()
%% Coloring = [{temp(), pos()}]
%% NumberOfSpills = integer()
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index 7852a2172b..0312e67822 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -74,7 +74,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
include ../native.mk
-ERL_COMPILE_FLAGS += +inline
+ERL_COMPILE_FLAGS += +inline +warn_unused_import +warn_exported_vars
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
index d147bed6d8..8831199244 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2007-2009. 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
@@ -42,6 +42,7 @@
%%--------------------------------------------------------------------
+%% ----- bs_start_match -----
gen_rtl({bs_start_match, 0}, [Ms], [Binary], TrueLblName, FalseLblName) ->
ReInitLbl = hipe_rtl:mk_new_label(),
BinaryLbl = hipe_rtl:mk_new_label(),
@@ -62,7 +63,7 @@ gen_rtl({bs_start_match, Max}, [Ms], [Binary], TrueLblName, FalseLblName) ->
TestCode =
[hipe_rtl:mk_move(Ms,Binary),
hipe_tagscheme:test_matchstate(Binary,
- hipe_rtl:label_name(MatchStateLbl),
+ hipe_rtl:label_name(MatchStateLbl),
hipe_rtl:label_name(BinaryLbl),
0.99)],
MatchStateTestCode =
@@ -86,7 +87,7 @@ gen_rtl({{bs_start_match, bitstr}, Max}, [Ms], [Binary],
gen_rtl({{bs_start_match, bitstr}, _Max}, [], [_Binary],
TrueLblName, _FalseLblName) ->
[hipe_rtl:mk_goto(TrueLblName)];
-gen_rtl({{bs_start_match,ok_matchstate}, Max}, [Ms], [Binary],
+gen_rtl({{bs_start_match, ok_matchstate}, Max}, [Ms], [Binary],
TrueLblName, FalseLblName) ->
MatchStateLbl = hipe_rtl:mk_new_label(),
BinaryLbl = hipe_rtl:mk_new_label(),
@@ -106,12 +107,13 @@ gen_rtl({{bs_start_match, ok_matchstate}, _Max}, [], [Binary],
hipe_rtl:label_name(MatchStateLbl), 0.99),
MatchStateLbl,
hipe_tagscheme:test_matchstate(Binary, TrueLblName, FalseLblName, 0.99)];
-gen_rtl({bs_get_integer, 0, _Flags}, [Dst, NewMs], [Ms],
+%% ----- bs_get_integer -----
+gen_rtl({bs_get_integer, 0, _Flags}, [Dst, NewMs], [Ms],
TrueLblName, _FalseLblName) ->
update_ms(NewMs, Ms) ++
[hipe_rtl:mk_move(Dst, hipe_rtl:mk_imm(15)),
hipe_rtl:mk_goto(TrueLblName)];
-gen_rtl({bs_get_integer,Size,Flags}, [Dst,NewMs], Args,
+gen_rtl({bs_get_integer, Size, Flags}, [Dst, NewMs], Args,
TrueLblName, FalseLblName) ->
case is_illegal_const(Size) of
true ->
@@ -123,15 +125,14 @@ gen_rtl({bs_get_integer,Size,Flags}, [Dst,NewMs], Args,
UnSafe = unsafe(Flags),
case Args of
[Ms] ->
- CCode= int_get_c_code(Dst, Ms, hipe_rtl:mk_imm(Size),
- Flags, TrueLblName, FalseLblName),
+ CCode = int_get_c_code(Dst, Ms, hipe_rtl:mk_imm(Size),
+ Flags, TrueLblName, FalseLblName),
update_ms(NewMs, Ms) ++
get_static_int(Dst, Ms, Size, CCode,
Signed, LittleEndian, Aligned, UnSafe,
TrueLblName, FalseLblName);
[Ms, Arg] ->
- {SizeCode1, SizeReg1} =
- make_size(Size, Arg, FalseLblName),
+ {SizeCode1, SizeReg1} = make_size(Size, Arg, FalseLblName),
CCode = int_get_c_code(Dst, Ms, SizeReg1, Flags,
TrueLblName, FalseLblName),
InCode = get_dynamic_int(Dst, Ms, SizeReg1, CCode,
@@ -140,7 +141,8 @@ gen_rtl({bs_get_integer,Size,Flags}, [Dst,NewMs], Args,
update_ms(NewMs, Ms) ++ SizeCode1 ++ InCode
end
end;
-gen_rtl({bs_get_float,Size,Flags}, [Dst1,NewMs], Args,
+%% ----- bs_get_float -----
+gen_rtl({bs_get_float,Size,Flags}, [Dst1, NewMs], Args,
TrueLblName, FalseLblName) ->
case is_illegal_const(Size) of
true ->
@@ -152,24 +154,26 @@ gen_rtl({bs_get_float,Size,Flags}, [Dst1,NewMs], Args,
CCode = float_get_c_code(Dst1, Ms, hipe_rtl:mk_imm(Size), Flags,
TrueLblName, FalseLblName),
update_ms(NewMs, Ms) ++ CCode;
- [Ms,Arg] ->
- {SizeCode, SizeReg} = make_size(Size, Arg,
- FalseLblName),
+ [Ms, Arg] ->
+ {SizeCode, SizeReg} = make_size(Size, Arg, FalseLblName),
CCode = float_get_c_code(Dst1, Ms, SizeReg, Flags,
TrueLblName, FalseLblName),
update_ms(NewMs, Ms) ++ SizeCode ++ CCode
end
end;
+%% ----- bs_get_binary_all -----
gen_rtl({bs_get_binary_all, Unit, _Flags}, [Dst], [Ms],
TrueLblName, FalseLblName) ->
[hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
get_binary_all(Dst, Unit, Ms, TrueLblName,FalseLblName);
-gen_rtl({bs_get_binary_all_2, Unit, _Flags}, [Dst,NewMs], [Ms],
+%% ----- bs_get_binary_all_2 -----
+gen_rtl({bs_get_binary_all_2, Unit, _Flags}, [Dst, NewMs], [Ms],
TrueLblName, FalseLblName) ->
[hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
update_ms(NewMs, Ms) ++
get_binary_all(Dst, Unit, Ms, TrueLblName, FalseLblName);
-gen_rtl({bs_get_binary,Size,Flags}, [Dst,NewMs], Args,
+%% ----- bs_get_binary -----
+gen_rtl({bs_get_binary, Size, Flags}, [Dst, NewMs], Args,
TrueLblName, FalseLblName) ->
case is_illegal_const(Size) of
true ->
@@ -188,65 +192,78 @@ gen_rtl({bs_get_binary,Size,Flags}, [Dst,NewMs], Args,
[hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
update_ms(NewMs, Ms) ++ SizeCode ++ InCode
end;
-gen_rtl(bs_get_utf8, [Dst,NewMs], [Ms], TrueLblName, FalseLblName) ->
+%% ----- bs_get_utf8 -----
+gen_rtl(bs_get_utf8, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
update_ms(NewMs, Ms) ++ utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName);
-gen_rtl({bs_get_utf16,Flags}, [Dst,NewMs], [Ms], TrueLblName, FalseLblName) ->
- update_ms(NewMs, Ms) ++ utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName);
-gen_rtl(bs_validate_unicode_retract, [NewMs], [Src,Ms], TrueLblName, FalseLblName) ->
- update_ms(NewMs, Ms) ++ validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName);
+%% ----- bs_get_utf16 -----
+gen_rtl({bs_get_utf16, Flags}, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
+ update_ms(NewMs, Ms) ++
+ utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName);
+%% ----- bs_validate_unicode_retract -----
+gen_rtl(bs_validate_unicode_retract, [NewMs], [Src, Ms],
+ TrueLblName, FalseLblName) ->
+ update_ms(NewMs, Ms) ++
+ validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName);
+%% ----- bs_test_tail -----
gen_rtl({bs_test_tail, NumBits}, [NewMs], [Ms], TrueLblName, FalseLblName) ->
{[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
update_ms(NewMs, Ms) ++ ExCode ++
[add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName),
hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)];
+%% ----- bs_test_unit -----
gen_rtl({bs_test_unit, Unit}, [], [Ms], TrueLblName, FalseLblName) ->
- {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
+ {[Offset, BinSize], ExCode} = extract_matchstate_vars([offset, binsize], Ms),
SizeReg = hipe_rtl:mk_new_reg(),
ExCode ++
[hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)|
test_alignment_code(SizeReg, Unit, TrueLblName, FalseLblName)];
gen_rtl({bs_test_tail, NumBits}, [], [Ms], TrueLblName, FalseLblName) ->
- {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
+ {[Offset, BinSize], ExCode} = extract_matchstate_vars([offset, binsize], Ms),
ExCode ++
[add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName),
hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)];
-gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms],
+%% ----- bs_skip_bits_all -----
+gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms],
TrueLblName, FalseLblName) ->
opt_update_ms(Dst, Ms) ++
skip_bits_all(Unit, Ms, TrueLblName, FalseLblName);
+%% ----- bs_skip_bits -----
gen_rtl({bs_skip_bits, Bits}, Dst, [Ms|Args], TrueLblName, FalseLblName) ->
- opt_update_ms(Dst,Ms) ++
- case Args of
- [] ->
- skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
- [Arg] ->
- {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
- InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
- SizeCode ++ InCode
- end;
+ opt_update_ms(Dst, Ms) ++
+ case Args of
+ [] ->
+ skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
+ [Arg] ->
+ {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
+ InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
+ SizeCode ++ InCode
+ end;
+%% ----- bs_restore -----
gen_rtl({bs_restore, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
update_ms(NewMs, Ms) ++
[get_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Tmp1),
set_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Tmp1),
hipe_rtl:mk_goto(TrueLblName)];
+%% ----- bs_save -----
gen_rtl({bs_save, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
{Offset, Instr} = extract_matchstate_var(offset, Ms),
update_ms(NewMs, Ms) ++
[Instr,
set_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Offset),
hipe_rtl:mk_goto(TrueLblName)];
-gen_rtl({bs_match_string, String, ByteSize}, [NewMs],
- [Ms], TrueLblName, FalseLblName) ->
+%% ----- bs_match_string -----
+gen_rtl({bs_match_string, String, ByteSize}, Dst, [Ms],
+ TrueLblName, FalseLblName) ->
{[Offset, BinSize, Base], Instrs} =
extract_matchstate_vars([offset, binsize, base], Ms),
[SuccessLbl, ALbl, ULbl] = create_lbls(3),
- [NewOffset,BitOffset] = create_gcsafe_regs(2),
+ [NewOffset, BitOffset] = create_gcsafe_regs(2),
Unit = hipe_rtl_arch:word_size() - 1,
Loops = ByteSize div Unit,
Init =
[Instrs,
- update_ms(NewMs,Ms),
+ opt_update_ms(Dst, Ms),
check_size(Offset, hipe_rtl:mk_imm(ByteSize*?BYTE_SIZE), BinSize,
NewOffset, hipe_rtl:label_name(SuccessLbl), FalseLblName),
SuccessLbl],
@@ -255,10 +272,10 @@ gen_rtl({bs_match_string, String, ByteSize}, [NewMs],
hipe_rtl:label_name(ALbl), hipe_rtl:label_name(ULbl))],
Loops = ByteSize div Unit,
SkipSize = Loops * Unit,
- {ACode1,UCode1} =
+ {ACode1, UCode1} =
case Loops of
0 ->
- {[],[]};
+ {[], []};
_ ->
create_loops(Loops, Unit, String, Base,
Offset, BitOffset, FalseLblName)
@@ -267,12 +284,17 @@ gen_rtl({bs_match_string, String, ByteSize}, [NewMs],
{ACode2, UCode2} =
case ByteSize rem Unit of
0 ->
- {[],[]};
+ {[], []};
Rem ->
create_rests(Rem, RestString, Base, Offset, BitOffset, FalseLblName)
end,
- End = [update_offset(NewOffset, NewMs), hipe_rtl:mk_goto(TrueLblName)],
- [Init, SplitCode, ALbl, ACode1, ACode2, End, ULbl, UCode1, UCode2,End];
+ GoTo = hipe_rtl:mk_goto(TrueLblName),
+ End = case Dst of
+ [] -> [GoTo];
+ [NewMs] -> [update_offset(NewOffset, NewMs), GoTo]
+ end,
+ [Init, SplitCode, ALbl, ACode1, ACode2, End, ULbl, UCode1, UCode2, End];
+%% ----- bs_context_to_binary -----
gen_rtl(bs_context_to_binary, [Bin], [Var], TrueLblName, _FalseLblName) ->
MSLabel = hipe_rtl:mk_new_label(),
[hipe_rtl:mk_move(Bin, Var),
@@ -304,9 +326,7 @@ get_c_code(Func, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
hipe_rtl_arch:call_bif([Dst1], Func, [SizeReg, FlagsReg, MatchBuf],
hipe_rtl:label_name(RetLabel), FalseLblName),
RetLabel,
- hipe_rtl:mk_branch(Dst1, eq, NonVal,
- FalseLblName,
- TrueLblName, 0.01)].
+ hipe_rtl:mk_branch(Dst1, eq, NonVal, FalseLblName, TrueLblName, 0.01)].
utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName) ->
MatchBuf = hipe_rtl:mk_new_reg(),
@@ -330,7 +350,7 @@ validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName) ->
Tmp = hipe_rtl:mk_new_reg(),
[hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
hipe_rtl_arch:call_bif([Tmp], bs_validate_unicode_retract,
- [MatchBuf,Src], [], []),
+ [MatchBuf, Src], [], []),
hipe_rtl:mk_branch(Tmp, eq, Zero, FalseLblName, TrueLblName, 0.01)].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Int Code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -464,9 +484,9 @@ get_int_from_unaligned_bin(Ms, Size, Dst1, Signed,
{[Base,Offset,BinSize], ExCode} =
extract_matchstate_vars([base,offset,binsize], Ms),
ExCode ++
- [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset,
- UnSafe, hipe_rtl:label_name(SuccessLbl), FalseLblName),
- SuccessLbl] ++
+ [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset,
+ UnSafe, hipe_rtl:label_name(SuccessLbl), FalseLblName),
+ SuccessLbl] ++
[update_offset(NewOffset, Ms)] ++
get_unaligned_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName).
@@ -499,7 +519,7 @@ make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName) ->
Offset = hipe_rtl:mk_new_reg_gcsafe(),
Lbl = hipe_rtl:mk_new_label(),
[hipe_rtl:mk_gctest(?MS_MIN_SIZE+Max),
- get_binary_bytes(Binary, BinSize, Base, Offset,
+ get_binary_bytes(Binary, BinSize, Base, Offset,
Orig, hipe_rtl:label_name(Lbl), FalseLblName),
Lbl,
hipe_tagscheme:create_matchstate(Max, BinSize, Base, Offset, Orig, Ms),
@@ -551,24 +571,22 @@ get_binary_all(Dst1, Unit, Ms, TrueLblName, FalseLblName) ->
hipe_rtl:mk_goto(TrueLblName)],
ExCode ++ MakeCode.
-get_binary(Dst1, Ms, SizeReg,
- UnSafe, TrueLblName, FalseLblName) ->
+get_binary(Dst1, Ms, SizeReg, UnSafe, TrueLblName, FalseLblName) ->
[SuccessLbl] = create_lbls(1),
[EndOffset] = create_gcsafe_regs(1),
{[Offset,BinSize,Orig], ExCode} =
extract_matchstate_vars([offset,binsize,orig], Ms),
CheckCode =
- [check_size(Offset, SizeReg, BinSize, EndOffset,
- UnSafe, hipe_rtl:label_name(SuccessLbl),
- FalseLblName),
+ [check_size(Offset, SizeReg, BinSize, EndOffset, UnSafe,
+ hipe_rtl:label_name(SuccessLbl), FalseLblName),
SuccessLbl],
MakeCode =
- construct_subbin(Dst1,SizeReg,Offset,Orig)
+ construct_subbin(Dst1, SizeReg, Offset, Orig)
++ [update_offset(EndOffset, Ms),
hipe_rtl:mk_goto(TrueLblName)],
ExCode ++ CheckCode ++ MakeCode.
-construct_subbin(Dst,Size,Offset,Orig) ->
+construct_subbin(Dst, Size, Offset, Orig) ->
[BitOffset, ByteOffset, BitSize, ByteSize] = create_gcsafe_regs(4),
[hipe_rtl:mk_alu(ByteSize, Size, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
hipe_rtl:mk_alu(BitSize, Size, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
@@ -579,12 +597,10 @@ construct_subbin(Dst,Size,Offset,Orig) ->
%%%%%%%%%%%%%%%%%%%%%%%%% Skip Bits %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-skip_bits_all(1, Ms, TrueLblName,_FalseLblName) ->
+skip_bits_all(1, Ms, TrueLblName, _FalseLblName) ->
{[BinSize], ExCode} = extract_matchstate_vars([binsize], Ms),
- ExCode ++
- [update_offset(BinSize,Ms),
- hipe_rtl:mk_goto(TrueLblName)];
-skip_bits_all(Unit,Ms, TrueLblName,FalseLblName) ->
+ ExCode ++ [update_offset(BinSize,Ms), hipe_rtl:mk_goto(TrueLblName)];
+skip_bits_all(Unit,Ms, TrueLblName, FalseLblName) ->
[Size] = create_gcsafe_regs(1),
[SuccessLbl] = create_lbls(1),
SLblName = hipe_rtl:label_name(SuccessLbl),
@@ -597,7 +613,7 @@ skip_bits_all(Unit,Ms, TrueLblName,FalseLblName) ->
update_offset(BinSize,Ms),
hipe_rtl:mk_goto(TrueLblName)].
-test_alignment_code(Size,Unit,SLblName,FalseLblName) ->
+test_alignment_code(Size, Unit, SLblName, FalseLblName) ->
case Unit of
1 -> [hipe_rtl:mk_goto(SLblName)];
2 -> get_fast_test_code(Size,1,SLblName,FalseLblName);
@@ -608,13 +624,13 @@ test_alignment_code(Size,Unit,SLblName,FalseLblName) ->
_ -> get_slow_test_code(Size,Unit,SLblName,FalseLblName)
end.
-get_fast_test_code(Size,AndTest,SLblName,FalseLblName) ->
+get_fast_test_code(Size, AndTest, SLblName, FalseLblName) ->
[Tmp] = create_gcsafe_regs(1),
- [hipe_rtl:mk_alub(Tmp,Size,'and',hipe_rtl:mk_imm(AndTest),
- eq,SLblName,FalseLblName)].
+ [hipe_rtl:mk_alub(Tmp, Size, 'and', hipe_rtl:mk_imm(AndTest),
+ 'eq', SLblName, FalseLblName)].
%% This is really slow
-get_slow_test_code(Size,Unit,SLblName,FalseLblName) ->
+get_slow_test_code(Size, Unit, SLblName, FalseLblName) ->
[Tmp] = create_gcsafe_regs(1),
[LoopLbl,Lbl1,Lbl2] = create_lbls(3),
LoopLblName = hipe_rtl:label_name(LoopLbl),
@@ -638,7 +654,7 @@ skip_bits2(Ms, NoOfBits, TrueLblName, FalseLblName) ->
[hipe_rtl:mk_branch(BinSize, 'ltu', NewOffset, FalseLblName,
hipe_rtl:label_name(TempLbl), 0.01),
TempLbl,
- update_offset(NewOffset,Ms),
+ update_offset(NewOffset, Ms),
hipe_rtl:mk_goto(TrueLblName)].
add_to_offset(Result, Extra, Original, FalseLblName) ->
@@ -685,7 +701,7 @@ get_base(Orig,Base) ->
[hipe_tagscheme:test_heap_binary(Orig, hipe_rtl:label_name(HeapLbl),
hipe_rtl:label_name(REFCLbl)),
HeapLbl,
- hipe_rtl:mk_alu(Base, Orig, add, hipe_rtl:mk_imm(?HEAP_BIN_DATA-2)),
+ hipe_rtl:mk_alu(Base, Orig, 'add', hipe_rtl:mk_imm(?HEAP_BIN_DATA-2)),
hipe_rtl:mk_goto(hipe_rtl:label_name(EndLbl)),
REFCLbl,
hipe_rtl:mk_load(Base, Orig, hipe_rtl:mk_imm(?PROC_BIN_BYTES-2)),
@@ -761,8 +777,7 @@ unsafe(Flags) ->
end.
update_offset(NewOffset, Ms) ->
- set_field_from_term({matchstate,{matchbuffer,offset}},
- Ms, NewOffset).
+ set_field_from_term({matchstate, {matchbuffer, offset}}, Ms, NewOffset).
opt_update_ms([NewMs], OldMs) ->
[hipe_rtl:mk_move(NewMs, OldMs)];
@@ -774,7 +789,7 @@ update_ms(NewMs, OldMs) ->
create_lbls(0) ->
[];
-create_lbls(X) when X > 0->
+create_lbls(X) when X > 0 ->
[hipe_rtl:mk_new_label()|create_lbls(X-1)].
make_dyn_prep(SizeReg, CCode) ->
@@ -1101,9 +1116,12 @@ multiply_code(List=[Head|_Tail], Variable, Result, FalseLblName) ->
multiply_code([ShiftSize|Rest], Register, Result, FalseLblName, Tmp1, OldCode) ->
SuccessLbl = hipe_rtl:mk_new_label(),
- Code = OldCode ++ [hipe_rtl:mk_alu(Tmp1, Register, sll, hipe_rtl:mk_imm(ShiftSize)),
- hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99),
- SuccessLbl],
+ Code =
+ OldCode ++
+ [hipe_rtl:mk_alu(Tmp1, Register, sll, hipe_rtl:mk_imm(ShiftSize)),
+ hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow,
+ hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99),
+ SuccessLbl],
multiply_code(Rest, Register, Result, FalseLblName, Tmp1, Code);
multiply_code([], _Register, _Result, _FalseLblName, _Tmp1, Code) ->
Code.
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index 0cc6c2deec..f1e8d1ef41 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -20,7 +20,7 @@
%%========================================================================
%%
%% Filename : hipe_tagscheme.erl
-%% Note : This is specific to Erlang 5.* (i.e. R9 to R13).
+%% Note : This is specific to Erlang 5.* (i.e. starting with R9).
%%
%% Modifications:
%% 020904: Happi - added support for external pids and ports.
diff --git a/lib/mnesia/test/mnesia.spec b/lib/mnesia/test/mnesia.spec
index 653e515317..e4746fe14c 100644
--- a/lib/mnesia/test/mnesia.spec
+++ b/lib/mnesia/test/mnesia.spec
@@ -1,4 +1,4 @@
-{suites,"../mnesia_test",all}.
+{suites,"../mnesia_test",[mnesia_SUITE]}.
{skip_cases,"../mnesia_test",mnesia_measure_test,
[ram_meter],
"Takes to long time"}.
diff --git a/lib/mnesia/test/mnesia_config_test.erl b/lib/mnesia/test/mnesia_config_test.erl
index f0f3053ebf..6baf86a4a5 100644
--- a/lib/mnesia/test/mnesia_config_test.erl
+++ b/lib/mnesia/test/mnesia_config_test.erl
@@ -596,8 +596,8 @@ dump_log_load_regulation(Config) when is_list(Config) ->
{n_branches, length(Nodes) * 10},
{n_accounts_per_branch, 5},
{replica_type, disc_copies},
- {stop_after, timer:seconds(30)},
- {report_interval, timer:seconds(10)},
+ {stop_after, timer:seconds(15)},
+ {report_interval, timer:seconds(3)},
{use_running_mnesia, true},
{reuse_history_id, true}],
diff --git a/lib/mnesia/test/mnesia_durability_test.erl b/lib/mnesia/test/mnesia_durability_test.erl
index 2fee72f066..1de62a7d25 100644
--- a/lib/mnesia/test/mnesia_durability_test.erl
+++ b/lib/mnesia/test/mnesia_durability_test.erl
@@ -100,14 +100,14 @@ load_latest_data(Config) when is_list(Config) ->
?match([], mnesia_test_lib:start_mnesia([N1], [])),
%% Should wait for N2
- ?match({timeout, [t1]}, rpc:call(N1, mnesia, wait_for_tables, [[t1], 3000])),
+ ?match({timeout, [t1]}, rpc:call(N1, mnesia, wait_for_tables, [[t1], 1000])),
?match([], mnesia_test_lib:start_mnesia([N3], [])),
- ?match({timeout, [t1]}, rpc:call(N1, mnesia, wait_for_tables, [[t1], 3000])),
+ ?match({timeout, [t1]}, rpc:call(N1, mnesia, wait_for_tables, [[t1], 1000])),
?match([], mnesia_test_lib:start_mnesia([N2], [])),
- ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[t1], 3000])),
- ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[t1], 3000])),
+ ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[t1], 10000])),
+ ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[t1], 10000])),
%% We should find the record
?match([Rec2], rpc:call(N1, mnesia, dirty_read, [t1, test])),
?match([Rec2], rpc:call(N2, mnesia, dirty_read, [t1, test])),
@@ -124,12 +124,12 @@ load_latest_data(Config) when is_list(Config) ->
?match([], mnesia_test_lib:start_mnesia([N2], [])),
%% Should wait for N1
- ?match({timeout, [t1]}, rpc:call(N2, mnesia, wait_for_tables, [[t1], 2000])),
+ ?match({timeout, [t1]}, rpc:call(N2, mnesia, wait_for_tables, [[t1], 1000])),
?match([], mnesia_test_lib:start_mnesia([N3], [])),
- ?match({timeout, [t1]}, rpc:call(N2, mnesia, wait_for_tables, [[t1], 2000])),
+ ?match({timeout, [t1]}, rpc:call(N2, mnesia, wait_for_tables, [[t1], 1000])),
?match([], mnesia_test_lib:start_mnesia([N1], [])),
- ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[t1], 1000])),
- ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[t1], 1000])),
+ ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[t1], 10000])),
+ ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[t1], 10000])),
%% We should find the record
?match([Rec1], rpc:call(N1, mnesia, dirty_read, [t1, test])),
?match([Rec1], rpc:call(N2, mnesia, dirty_read, [t1, test])),
diff --git a/lib/mnesia/test/mnesia_examples_test.erl b/lib/mnesia/test/mnesia_examples_test.erl
index 373d47a05a..219f358fdb 100644
--- a/lib/mnesia/test/mnesia_examples_test.erl
+++ b/lib/mnesia/test/mnesia_examples_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -34,32 +34,6 @@ end_per_testcase(Func, Conf) ->
delete_schema],
N, Config, ?FILE, ?LINE)).
-opt_net_load(ExampleMod) ->
- opt_net_load([node() | nodes()], ExampleMod, ok).
-
-opt_net_load([Node | Nodes], ExampleMod, Res) ->
- case rpc:call(Node, ?MODULE, opt_load, [ExampleMod]) of
- {module, ExampleMod} ->
- opt_net_load(Nodes, ExampleMod, Res);
- {error, Reason} ->
- Error = {opt_net_load, ExampleMod, Node, Reason},
- opt_net_load(Nodes, ExampleMod, {error, Error});
- {badrpc, Reason} ->
- Error = {opt_net_load, ExampleMod, Node, Reason},
- opt_net_load(Nodes, ExampleMod, {error, Error})
- end;
-opt_net_load([], _ExampleMod, Res) ->
- Res.
-
-opt_load(Mod) ->
- case code:is_loaded(Mod) of
- {file, _} ->
- {module, Mod};
- false ->
- Abs = filename:join([code:lib_dir(mnesia), examples, Mod]),
- code:load_abs(Abs)
- end.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
all() ->
[bup, company, meter, {group, tpcb}].
@@ -95,49 +69,49 @@ replica_test(suite) -> [];
replica_test(Config) when is_list(Config) ->
?init(3, Config),
opt_net_load(mnesia_tpcb),
- ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(replica_test, ram_copies))).
+ ?match({ok, _}, mnesia_tpcb:start(config(replica_test, ram_copies))).
sticky_replica_test(suite) -> [];
sticky_replica_test(Config) when is_list(Config) ->
?init(3, Config),
opt_net_load(mnesia_tpcb),
- ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(sticky_replica_test, ram_copies))).
+ ?match({ok, _}, mnesia_tpcb:start(config(sticky_replica_test, ram_copies))).
dist_test(suite) -> [];
dist_test(Config) when is_list(Config) ->
?init(3, [{tc_timeout, timer:minutes(10)} | Config]),
opt_net_load(mnesia_tpcb),
- ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(dist_test, ram_copies))).
+ ?match({ok, _}, mnesia_tpcb:start(config(dist_test, ram_copies))).
conflict_test(suite) -> [];
conflict_test(Config) when is_list(Config) ->
?init(3, Config),
opt_net_load(mnesia_tpcb),
- ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(conflict_test, ram_copies))).
+ ?match({ok, _}, mnesia_tpcb:start(config(conflict_test, ram_copies))).
frag_test(suite) -> [];
frag_test(Config) when is_list(Config) ->
?init(3, Config),
opt_net_load(mnesia_tpcb),
- ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(frag_test, ram_copies))).
+ ?match({ok, _}, mnesia_tpcb:start(config(frag_test, ram_copies))).
frag2_test(suite) -> [];
frag2_test(Config) when is_list(Config) ->
?init(3, Config),
opt_net_load(mnesia_tpcb),
- ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(frag2_test, ram_copies))).
+ ?match({ok, _}, mnesia_tpcb:start(config(frag2_test, ram_copies))).
remote_test(suite) -> [];
remote_test(Config) when is_list(Config) ->
?init(3, Config),
opt_net_load(mnesia_tpcb),
- ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(remote_test, ram_copies))).
+ ?match({ok, _}, mnesia_tpcb:start(config(remote_test, ram_copies))).
remote_frag2_test(suite) -> [];
remote_frag2_test(Config) when is_list(Config) ->
?init(3, Config),
opt_net_load(mnesia_tpcb),
- ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(remote_frag2_test, ram_copies))).
+ ?match({ok, _}, mnesia_tpcb:start(config(remote_frag2_test, ram_copies))).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
meter(doc) ->
@@ -149,4 +123,37 @@ meter(Config) when is_list(Config) ->
opt_net_load(mnesia_meter),
?match(ok, mnesia_meter:go(ram_copies, [N])).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+config(Test, Type) ->
+ Config0 = mnesia_tpcb:config(Test, Type),
+ %% Cut the times, the idea is to test the example and configuration
+ %% not running the test a long time
+ Config1 = lists:keyreplace(stop_after, 1, Config0, {stop_after, 6000}),
+ lists:keyreplace(report_interval, 1, Config1, {report_interval, 1000}).
+
+opt_net_load(ExampleMod) ->
+ opt_net_load([node() | nodes()], ExampleMod, ok).
+
+opt_net_load([Node | Nodes], ExampleMod, Res) ->
+ case rpc:call(Node, ?MODULE, opt_load, [ExampleMod]) of
+ {module, ExampleMod} ->
+ opt_net_load(Nodes, ExampleMod, Res);
+ {error, Reason} ->
+ Error = {opt_net_load, ExampleMod, Node, Reason},
+ opt_net_load(Nodes, ExampleMod, {error, Error});
+ {badrpc, Reason} ->
+ Error = {opt_net_load, ExampleMod, Node, Reason},
+ opt_net_load(Nodes, ExampleMod, {error, Error})
+ end;
+opt_net_load([], _ExampleMod, Res) ->
+ Res.
+opt_load(Mod) ->
+ case code:is_loaded(Mod) of
+ {file, _} ->
+ {module, Mod};
+ false ->
+ Abs = filename:join([code:lib_dir(mnesia), examples, Mod]),
+ code:load_abs(Abs)
+ end.
diff --git a/lib/mnesia/test/mnesia_recovery_test.erl b/lib/mnesia/test/mnesia_recovery_test.erl
index c4910a4b11..0d0ad32fb0 100644
--- a/lib/mnesia/test/mnesia_recovery_test.erl
+++ b/lib/mnesia/test/mnesia_recovery_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. 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
@@ -607,7 +607,7 @@ explicit_stop_during_snmp(Config) when is_list(Config) ->
Do_trans_Pid1 = spawn_link(Node2, ?MODULE, do_trans_loop, [Tab, self()]),
Do_trans_Pid2 = spawn_link(?MODULE, do_trans_loop, [Tab, self()]),
- Start_stop_Pid = spawn_link(?MODULE, start_stop, [Node1, 10, self()]),
+ Start_stop_Pid = spawn_link(?MODULE, start_stop, [Node1, 5, self()]),
receive
test_done ->
ok
@@ -631,13 +631,13 @@ do_trans_loop2(Tab, Father) ->
end,
case mnesia:transaction(Trans) of
{atomic, ok} ->
- timer:sleep(200),
+ timer:sleep(100),
do_trans_loop2(Tab, Father);
{aborted, {node_not_running, N}} when N == node() ->
- timer:sleep(200),
+ timer:sleep(100),
do_trans_loop2(Tab, Father);
{aborted, {no_exists, Tab}} ->
- timer:sleep(200),
+ timer:sleep(100),
do_trans_loop2(Tab, Father);
Else ->
?error("Transaction failed: ~p ~n", [Else]),
@@ -649,9 +649,9 @@ start_stop(_Node1, 0, Father) ->
Father ! test_done,
exit(shutdown);
start_stop(Node1, N, Father) when N > 0->
- timer:sleep(timer:seconds(5)),
- ?match(stopped, rpc:call(Node1, mnesia, stop, [])),
timer:sleep(timer:seconds(2)),
+ ?match(stopped, rpc:call(Node1, mnesia, stop, [])),
+ timer:sleep(timer:seconds(1)),
?match([], mnesia_test_lib:start_mnesia([Node1])),
start_stop(Node1, N-1, Father).
diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c
index a6b3de6e48..5730e20774 100644
--- a/lib/odbc/c_src/odbcserver.c
+++ b/lib/odbc/c_src/odbcserver.c
@@ -1222,7 +1222,7 @@ static db_result_msg encode_out_params(db_state *state,
(column.type.strlen_or_indptr_array[j]));
break;
case SQL_C_SLONG:
- ei_x_encode_long(&dynamic_buffer(state), ((long*)values)[j]);
+ ei_x_encode_long(&dynamic_buffer(state), ((SQLINTEGER*)values)[j]);
break;
case SQL_C_DOUBLE:
ei_x_encode_double(&dynamic_buffer(state),
diff --git a/lib/odbc/test/odbc_query_SUITE.erl b/lib/odbc/test/odbc_query_SUITE.erl
index 062373afa0..56550bfaa6 100644
--- a/lib/odbc/test/odbc_query_SUITE.erl
+++ b/lib/odbc/test/odbc_query_SUITE.erl
@@ -43,7 +43,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
case odbc_test_lib:odbc_check() of
ok ->
- [sql_query, next, {group, scrollable_cursors}, select_count,
+ [stored_proc, sql_query, next, {group, scrollable_cursors}, select_count,
select_next, select_relative, select_absolute,
create_table_twice, delete_table_twice, duplicate_key,
not_connection_owner, no_result_set, query_error,
@@ -172,6 +172,26 @@ end_per_testcase(_Case, Config) ->
%%-------------------------------------------------------------------------
%% Test cases starts here.
%%-------------------------------------------------------------------------
+stored_proc(doc)->
+ ["Test stored proc with OUT param"];
+stored_proc(suite) -> [];
+stored_proc(Config) when is_list(Config) ->
+ case ?RDBMS of
+ X when X == oracle; X == postgres->
+ Ref = ?config(connection_ref, Config),
+ {updated, _} =
+ odbc:sql_query(Ref,
+ ?RDBMS:stored_proc_integer_out()),
+ Result = ?RDBMS:query_result(),
+ Result =
+ ?RDBMS:param_query(Ref),
+ {updated, _} =
+ odbc:sql_query(Ref, ?RDBMS:drop_proc()),
+ ok;
+ _ ->
+ {skip, "stored proc not yet supported"}
+ end.
+
sql_query(doc)->
["Test the common cases"];
sql_query(suite) -> [];
diff --git a/lib/odbc/test/oracle.erl b/lib/odbc/test/oracle.erl
index d74863d8c1..95cf7155dc 100644
--- a/lib/odbc/test/oracle.erl
+++ b/lib/odbc/test/oracle.erl
@@ -240,3 +240,30 @@ describe_floating() ->
{ok,[{"F",sql_double},{"R",sql_double},{"D",sql_double}]}.
describe_dec_num() ->
{ok,[{"MYDEC",{sql_decimal,9,3}},{"MYNUM",{sql_decimal,9,2}}]}.
+
+%-------------------------------------------------------------------------
+drop_proc() ->
+ "drop procedure test_proc1;".
+
+stored_proc_integer_out() ->
+ "create or replace PROCEDURE test_proc1(" ++
+ "int_a OUT NUMBER, " ++
+ "int_b OUT NUMBER) " ++
+ "is " ++
+ "begin " ++
+ " int_a := 123; " ++
+ " int_b := 456; " ++
+ "exception " ++
+ "WHEN NO_DATA_FOUND THEN " ++
+ " int_a := 0; " ++
+ " int_b := 0; " ++
+ "end;".
+
+param_query(Ref) ->
+ odbc:param_query(Ref, "call test_proc1(?,?)",
+ [{sql_integer, out, [0]},
+ {sql_integer, out, [0]}]).
+
+
+query_result() ->
+ {executed, 2, [{123, 456}]}.
diff --git a/lib/odbc/test/postgres.erl b/lib/odbc/test/postgres.erl
index d564dbd5ff..0c1761b835 100644
--- a/lib/odbc/test/postgres.erl
+++ b/lib/odbc/test/postgres.erl
@@ -293,3 +293,42 @@ describe_dec_num() ->
describe_timestamp() ->
{ok, [{"field", sql_timestamp}]}.
+
+%-------------------------------------------------------------------------
+drop_proc() ->
+ "drop function test_proc1(OUT integer, OUT integer);".
+
+stored_proc_integer_out() ->
+ "create or replace FUNCTION test_proc1(" ++
+ "OUT int_a INTEGER, " ++
+ "OUT int_b INTEGER) " ++
+ "AS $$ " ++
+ "BEGIN " ++
+ " int_a := 123; " ++
+ " int_b := 456; " ++
+ "END " ++
+ "$$ LANGUAGE plpgsql ".
+
+%% This does not test what you might think it is supposed to test.
+%% Since the stored procedure has got 2 out parameters and no
+%% in parameters it is of arity 0 as called below.
+%%
+%% The port program odbcserver.c will marshal these out parameters
+%% and hand them to ODBC. The ODBC driver for postgres will
+%% apparently not give a hoot about these out parameters and instead
+%% return the result in a regular result select set. The port program
+%% will assume it has the result in the out parameters and marshal
+%% these as they are i.e as it itself had packed them, so they
+%% come back unchanged.
+%%
+%% The real function result goes into the void but the code in odbcserver.c
+%% that marshals out parameters returned from ODBC will be run
+%% so that is what this test tests...
+%%
+param_query(Ref) ->
+ odbc:param_query(Ref, "select * from test_proc1()",
+ [{sql_integer, out, [111]},
+ {sql_integer, out, [444]}]).
+
+query_result() ->
+ {executed, 2, [{111, 444}]}.
diff --git a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl
index 768653c898..aa582d1d4e 100644
--- a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl
+++ b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl
@@ -30,7 +30,7 @@
-include("CosNaming_NamingContext.hrl").
-include("CosNaming_NamingContextExt.hrl").
-include_lib("orber/include/corba.hrl").
-
+-include_lib("orber/src/orber_iiop.hrl").
%%-----------------------------------------------------------------
%% External exports
@@ -182,6 +182,8 @@ address(protocol, [$:|T], [], []) ->
address(version, T, [], [iiop]);
address(protocol, [$i, $i, $o, $p, $:|T], [], []) ->
address(version, T, [], [iiop]);
+address(protocol, [$s,$s,$l, $i, $o, $p, $:|T], [], []) ->
+ address(version, T, [], [ssliop]);
address(protocol, [$r, $i, $r, $:|T], [], []) ->
{false, rir, T};
address(protocol, What, _, _) ->
@@ -465,6 +467,20 @@ lookup({corbaname, [[iiop, Vers, Host, Port]|Addresses], Key, Name}, Ctx) ->
Obj ->
Obj
end;
+%%% Corbaname via SSL
+lookup({corbaname, [[ssliop, Vers, Host, Port]|Addresses], Key, Name}, Ctx) ->
+ SSLComponent =
+ #'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
+ component_data=#'SSLIOP_SSL'{target_supports = 2,
+ target_requires = 2,
+ port = Port}},
+ NS = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key, [SSLComponent]),
+ case catch 'CosNaming_NamingContext':resolve(NS, Ctx, Name) of
+ {'EXCEPTION', _} ->
+ lookup({corbaname, Addresses, Key, Name}, Ctx);
+ Obj ->
+ Obj
+ end;
lookup({corbaname, [_|Addresses], Key, Name}, Ctx) ->
lookup({corbaname, Addresses, Key, Name}, Ctx);
@@ -498,7 +514,43 @@ lookup({corbaloc, [[iiop, Vers, Host, Port]|Addresses], Key}, Ctx) ->
lookup({corbaloc, Addresses, Key}, Ctx)
end
end;
-
+
+%%% Corbaloc via SSL
+lookup({corbaloc, [[ssliop, Vers, Host, Port]|Addresses], Key}, Ctx) ->
+ SSLComponent =
+ #'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
+ component_data=#'SSLIOP_SSL'{target_supports = 2,
+ target_requires = 2,
+ port = Port}},
+ ObjRef = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key, [SSLComponent]),
+ OldVal = put(orber_forward_notify, true),
+
+ case catch corba_object:non_existent(ObjRef, Ctx) of
+ {location_forward, Result} ->
+ put(orber_forward_notify, OldVal),
+ Result;
+ false ->
+ put(orber_forward_notify, OldVal),
+ ObjRef;
+ true ->
+ put(orber_forward_notify, OldVal),
+ lookup({corbaloc, Addresses, Key}, Ctx);
+ _ ->
+ %% May be located on a version using '_not_existent'
+ %% see CORBA2.3.1 page 15-34 try again.
+ case catch corba_object:not_existent(ObjRef, Ctx) of
+ {location_forward, Result} ->
+ put(orber_forward_notify, OldVal),
+ Result;
+ false ->
+ put(orber_forward_notify, OldVal),
+ ObjRef;
+ _ ->
+ put(orber_forward_notify, OldVal),
+ lookup({corbaloc, Addresses, Key}, Ctx)
+ end
+ end;
+
lookup({corbaloc, [_|Addresses], Key}, Ctx) ->
lookup({corbaloc, Addresses, Key}, Ctx);
diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml
index d43ab3ac24..9e896f03c8 100644
--- a/lib/orber/doc/src/notes.xml
+++ b/lib/orber/doc/src/notes.xml
@@ -32,6 +32,22 @@
<file>notes.xml</file>
</header>
+
+ <section><title>Orber 3.6.26</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bug in corbaloc/corbaname over ssl.</p>
+ <p>
+ Own Id: OTP-10675</p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
<section><title>Orber 3.6.25</title>
<section><title>Improvements and New Features</title>
@@ -45,7 +61,6 @@
</list>
</section>
-
<section><title>Known Bugs and Problems</title>
<list>
<item>
@@ -57,7 +72,6 @@
</item>
</list>
</section>
-
</section>
<section><title>Orber 3.6.24</title>
diff --git a/lib/orber/src/orber_env.erl b/lib/orber/src/orber_env.erl
index 8758450104..67d31018ff 100644
--- a/lib/orber/src/orber_env.erl
+++ b/lib/orber/src/orber_env.erl
@@ -302,6 +302,7 @@ create_security_info(ssl, Info) ->
"SSL IIOP accept timeout.......: ~p~n"
"SSL IIOP backlog..............: ~p~n"
"SSL IIOP Local Interface......: ~p~n"
+ "SSL server options............: ~p~n"
"SSL server certfile...........: ~p~n"
"SSL server verification type..: ~p~n"
"SSL server verification depth.: ~p~n"
@@ -310,6 +311,7 @@ create_security_info(ssl, Info) ->
"SSL server password...........: ~p~n"
"SSL server ciphers............: ~p~n"
"SSL server cachetimeout.......: ~p~n"
+ "SSL client options............: ~p~n"
"SSL client certfile...........: ~p~n"
"SSL client verification type..: ~p~n"
"SSL client verification depth.: ~p~n"
@@ -323,10 +325,12 @@ create_security_info(ssl, Info) ->
iiop_ssl_in_keepalive(), iiop_ssl_out_keepalive(),
nat_iiop_ssl_port(), iiop_ssl_accept_timeout(),
iiop_ssl_backlog(), iiop_ssl_ip_address_local(),
+ ssl_server_options(),
ssl_server_certfile(), ssl_server_verify(),
ssl_server_depth(), ssl_server_cacertfile(),
ssl_server_keyfile(), ssl_server_password(),
ssl_server_ciphers(), ssl_server_cachetimeout(),
+ ssl_client_options(),
ssl_client_certfile(), ssl_client_verify(),
ssl_client_depth(), ssl_client_cacertfile(),
ssl_client_keyfile(), ssl_client_password(),
diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk
index 10b19477e0..4e09532f88 100644
--- a/lib/orber/vsn.mk
+++ b/lib/orber/vsn.mk
@@ -1,3 +1,2 @@
-
-ORBER_VSN = 3.6.25
+ORBER_VSN = 3.6.26
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 5e25f22a6f..97785ca7f8 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -973,7 +973,8 @@ refresh_app(#app{name = AppName,
is_escript = IsEscript,
active_dir = ActiveDir,
label = OptLabel,
- mods = Mods} = App,
+ mods = Mods,
+ status = AppStatus} = App,
Force,
Status) ->
if
@@ -993,6 +994,8 @@ refresh_app(#app{name = AppName,
read_app_info(AppFile,
AppFile,
AppName,
+ ActiveDir,
+ AppStatus,
DefaultVsn,
Status),
@@ -1064,9 +1067,11 @@ refresh_app(#app{name = AppName,
missing_app_info(Vsn) ->
#app_info{vsn = Vsn}.
-read_app_info(_AppFileOrBin, _AppFile, erts, DefaultVsn, Status) ->
+read_app_info(_AppFileOrBin, _AppFile, erts, _ActiveDir, _AppStatus, DefaultVsn, Status) ->
{missing_app_info(DefaultVsn), Status};
-read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) ->
+read_app_info(_AppFileOrBin, _AppFile, _AppName, undefined, missing, DefaultVsn, Status) ->
+ {missing_app_info(DefaultVsn), Status};
+read_app_info(AppFileOrBin, AppFile, AppName, _ActiveDir, _AppStatus, DefaultVsn, Status) ->
EnoentText = file:format_error(enoent),
case reltool_utils:prim_consult(AppFileOrBin) of
{ok, [{application, AppName, Info}]} ->
@@ -1080,9 +1085,9 @@ read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) ->
Status)};
{error, Text} when Text =:= EnoentText ->
{missing_app_info(DefaultVsn),
- reltool_utils:add_warning("~w: Missing app file ~tp.",
- [AppName,AppFile],
- Status)};
+ reltool_utils:add_warning("~w: Missing app file ~tp.",
+ [AppName,AppFile],
+ Status)};
{error, Text} ->
{missing_app_info(DefaultVsn),
reltool_utils:add_warning("~w: Cannot parse app file ~tp (~tp).",
@@ -1773,13 +1778,15 @@ escripts_to_apps([Escript | Escripts], Apps, Status) ->
get_vsn_from_dir(AppName,AppLabel),
AppFileName =
filename:join([Escript, FullName]),
+ Dir = filename:join([Escript, AppName]),
{Info, StatusAcc2} =
read_app_info(GetBin(),
AppFileName,
AppName,
+ Dir,
+ ok,
DefaultVsn,
Status),
- Dir = filename:join([Escript, AppName]),
{[{AppName, app, Dir, Info} | FileAcc],
StatusAcc2};
E when E =:= Ext ->
@@ -1979,20 +1986,27 @@ refresh_apps(ConfigApps, [New | NewApps], Acc, Force, Status) ->
refresh_apps(_ConfigApps, [], Acc, _Force, Status) ->
{lists:reverse(Acc), Status}.
-
ensure_app_info(#app{is_escript = IsEscript, active_dir = Dir, info = Info},
Status)
when IsEscript=/=false ->
%% Escript or application which is inlined in an escript
{Info, Dir, Status};
-ensure_app_info(#app{name = Name, sorted_dirs = []}, _Status) ->
- reltool_utils:throw_error("~w: : Missing application directory.",[Name]);
+ensure_app_info(#app{name = Name, sorted_dirs = []} = App, Status) ->
+ Reason = "~w: Missing application directory.",
+ case App of
+ #app{incl_cond = exclude, status = missing, active_dir = Dir} ->
+ Status2 = reltool_utils:add_warning(Reason, [Name], Status),
+ {missing_app_info(""), Dir, Status2};
+ _ ->
+ reltool_utils:throw_error(Reason, [Name])
+ end;
ensure_app_info(#app{name = Name,
vsn = Vsn,
use_selected_vsn = UseSelectedVsn,
active_dir = ActiveDir,
sorted_dirs = Dirs,
- info = undefined},
+ info = undefined,
+ status = AppStatus},
Status) ->
ReadInfo =
fun(Dir, StatusAcc) ->
@@ -2000,7 +2014,8 @@ ensure_app_info(#app{name = Name,
Ebin = filename:join([Dir, "ebin"]),
DefaultVsn = get_vsn_from_dir(Name,Base),
AppFile = filename:join([Ebin, atom_to_list(Name) ++ ".app"]),
- read_app_info(AppFile, AppFile, Name, DefaultVsn, StatusAcc)
+ read_app_info(AppFile, AppFile, Name, ActiveDir,
+ AppStatus, DefaultVsn, StatusAcc)
end,
{AllInfo, Status2} = lists:mapfoldl(ReadInfo, Status, Dirs),
AllVsns = [I#app_info.vsn || I <- AllInfo],
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 23338d9ecd..adea716e99 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -80,6 +80,8 @@ all() ->
otp_9229_dupl_mod_exclude_app,
otp_9229_dupl_mod_exclude_mod,
dupl_mod_in_app_file,
+ include_non_existing_app,
+ exclude_non_existing_app,
get_apps,
get_mod,
get_sys,
@@ -1313,7 +1315,6 @@ otp_9229_dupl_mod_exclude_mod(Config) ->
ok.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test that if a module is duplicated in a .app file, then a warning
%% is produced, but target can still be created.
@@ -1346,6 +1347,56 @@ dupl_mod_in_app_file(Config) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test that a reasonable error message is returned if an application
+%% is missing
+include_non_existing_app(_Config) ->
+ %% Configure the server
+ Sys =
+ {sys,
+ [
+ {incl_cond,exclude},
+ {app,foobar,[{incl_cond,include}]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]}
+ ]},
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "target_include_non_existing_app"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
+ ?m({error,"foobar: Missing application directory."},
+ reltool:get_status([{config, Sys}])),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test that if a missing application is explicitly excluded a warning
+%% should be issued.
+exclude_non_existing_app(_Config) ->
+ %% Configure the server
+ Sys =
+ {sys,
+ [
+ {incl_cond,exclude},
+ {app,foobar,[{incl_cond,exclude}]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]}
+ ]},
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "target_exclude_non_existing_app"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
+ ?m({ok,["foobar: Missing application directory."]},
+ reltool:get_status([{config, Sys}])),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test the interface used by the GUI:
%% get_app
%% get_apps
diff --git a/lib/snmp/include/.gitignore b/lib/snmp/include/.gitignore
new file mode 100644
index 0000000000..4db987f64a
--- /dev/null
+++ b/lib/snmp/include/.gitignore
@@ -0,0 +1,4 @@
+*.hrl
+!SNMPv2-TC.hrl
+!snmp_tables.hrl
+!snmp_types.hrl
diff --git a/lib/snmp/priv/mibs/.gitignore b/lib/snmp/priv/mibs/.gitignore
index e69de29bb2..a8a0dcec44 100644
--- a/lib/snmp/priv/mibs/.gitignore
+++ b/lib/snmp/priv/mibs/.gitignore
@@ -0,0 +1 @@
+*.bin
diff --git a/lib/snmp/test/snmp_test_data/.gitignore b/lib/snmp/test/snmp_test_data/.gitignore
new file mode 100644
index 0000000000..c7cffa7f6d
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/.gitignore
@@ -0,0 +1,2 @@
+*.bin
+*.hrl
diff --git a/lib/ssh/doc/html/.gitignore b/lib/ssh/doc/html/.gitignore
index e69de29bb2..72e8ffc0db 100644
--- a/lib/ssh/doc/html/.gitignore
+++ b/lib/ssh/doc/html/.gitignore
@@ -0,0 +1 @@
+*
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index e9858a3220..2501db858a 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -79,6 +79,7 @@
{keyfile, path()} | {password, string()} |
{cacerts, [der_encoded()]} | {cacertfile, path()} |
|{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} |
+ {user_lookup_fun, {fun(), term()}}, {psk_identity, string()}, {srp_identity, {string(), string()}} |
{ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()}
{next_protocols_advertised, [binary()]} |
{client_preferred_next_protocols, client | server, [binary()]}
@@ -123,6 +124,7 @@
{key_exchange(), cipher(), hash()}</c></p>
<p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon
+ | psk | dhe_psk | rsa_psk | srp_anon | srp_dss | srp_rsa
</c></p>
<p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc'
@@ -134,6 +136,9 @@
<p><c>prf_random() = client_random | server_random
</c></p>
+ <p><c>srp_param_type() = srp_1024 | srp_1536 | srp_2048 | srp_3072
+ | srp_4096 | srp_6144 | srp_8192</c></p>
+
</section>
<section>
@@ -179,13 +184,16 @@
<tag>{ciphers, ciphers()}</tag>
<item>The cipher suites that should be supported. The function
- <c>cipher_suites/0</c> can be used to find all available
- ciphers. Additionally some anonymous cipher 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}) are supported for testing purposes and will
- only work if explicitly enabled by this option and they are supported/enabled
- by the peer also.
+ <c>cipher_suites/0</c> can be used to find all ciphers that are
+ supported by default. <c>cipher_suites(all)</c> may be called
+ to find all available cipher suites.
+ Pre-Shared Key (<url href="http://www.ietf.org/rfc/rfc4279.txt">RFC 4279</url> and
+ <url href="http://www.ietf.org/rfc/rfc5487.txt">RFC 5487</url>),
+ Secure Remote Password (<url href="http://www.ietf.org/rfc/rfc5054.txt">RFC 5054</url>)
+ and anonymous cipher suites only work if explicitly enabled by
+ this option and they are supported/enabled by the peer also.
+ Note that anonymous cipher suites are supported for testing purposes
+ only and should not be used when security matters.
</item>
<tag>{ssl_imp, new | old}</tag>
@@ -195,10 +203,10 @@
<tag>{secure_renegotiate, boolean()}</tag>
<item>Specifies if to reject renegotiation attempt that does
- not live up to RFC 5746. By default secure_renegotiate is
+ not live up to <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>. By default secure_renegotiate is
set to false i.e. secure renegotiation will be used if possible
but it will fallback to unsecure renegotiation if the peer
- does not support RFC 5746.
+ does not support <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>.
</item>
<tag>{depth, integer()}</tag>
@@ -292,6 +300,32 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<c>undefined</c> is specified (this is the default), the process
will never go into hibernation.
</item>
+
+ <tag>{user_lookup_fun, {Lookupfun :: fun(), UserState :: term()}}</tag>
+ <item>
+ <p>The lookup fun should be defined as:</p>
+ <code>
+fun(psk, PSKIdentity, UserState :: term()) ->
+ {ok, SharedSecret :: binary()} | error;
+fun(srp, Username, UserState :: term()) ->
+ {ok, {SRPParams :: srp_param_type(), Salt :: binary(), DerivedKey :: binary()}} | error.
+ </code>
+
+ <p>For Pre-Shared Key (PSK) cipher suites, the lookup fun will
+ be called by the client and server to determine the shared
+ secret. When called by the client, PSKIdentity will be set to the
+ hint presented by the server or undefined. When called by the
+ server, PSKIdentity is the identity presented by the client.
+ </p>
+
+ <p>For Secure Remote Password (SRP), the fun will only be used by the server to obtain
+ parameters that it will use to generate its session keys. <c>DerivedKey</c> should be
+ derived according to <url href="http://tools.ietf.org/html/rfc2945#section-3"> RFC 2945</url> and
+ <url href="http://tools.ietf.org/html/rfc5054#section-2.4"> RFC 5054</url>:
+ <c>crypto:sha([Salt, crypto:sha([Username, &lt;&lt;$:&gt;&gt;, Password])]) </c>
+ </p>
+ </item>
+
</taglist>
</section>
@@ -334,6 +368,14 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
server does not support Next Protocol Negotiation the
connection will be aborted if no default protocol is supplied.</p>
</item>
+
+ <tag>{psk_identity, string()}</tag>
+ <item>Specifies the identity the client presents to the server. The matching secret is
+ found by calling the user_look_fun.
+ </item>
+ <tag>{srp_identity, {Username :: string(), Password :: string()}</tag>
+ <item>Specifies the Username and Password to use to authenticate to the server.
+ </item>
</taglist>
</section>
@@ -396,6 +438,10 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
using <c>negotiated_next_protocol/1</c> method.
</item>
+ <tag>{psk_identity, string()}</tag>
+ <item>Specifies the server identity hint the server presents to the client.
+ </item>
+
</taglist>
</section>
@@ -427,13 +473,16 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<name>cipher_suites(Type) -> ciphers()</name>
<fsummary> Returns a list of supported cipher suites</fsummary>
<type>
- <v>Type = erlang | openssl</v>
+ <v>Type = erlang | openssl | all</v>
</type>
<desc><p>Returns a list of supported cipher suites.
cipher_suites() is equivalent to cipher_suites(erlang).
Type openssl is provided for backwards compatibility with
- old ssl that used openssl.
+ old ssl that used openssl. cipher_suites(all) returns
+ all available cipher suites. The cipher suites not present
+ in cipher_suites(erlang) but in included in cipher_suites(all)
+ will not be used unless explicitly configured by the user.
</p>
</desc>
</func>
@@ -821,7 +870,6 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
</desc>
</func>
-
</funcs>
<section>
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index e61f415c84..d3ba76d34e 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -50,6 +50,7 @@ MODULES= \
ssl_certificate\
ssl_certificate_db\
ssl_cipher \
+ ssl_srp_primes \
ssl_connection \
ssl_connection_sup \
ssl_handshake \
@@ -65,7 +66,7 @@ MODULES= \
INTERNAL_HRL_FILES = \
ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \
- ssl_record.hrl
+ ssl_record.hrl ssl_srp.hrl ssl_srp_primes.hrl
ERL_FILES= \
$(MODULES:%=%.erl) \
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 897a097f73..5c34de905e 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -20,6 +20,7 @@
ssl_connection_sup,
ssl_connection,
ssl_cipher,
+ ssl_srp_primes,
ssl_certificate_db,
ssl_certificate,
ssl_alert
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index fc06b5f1b0..70f3b4f050 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -37,6 +37,7 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_handshake.hrl").
+-include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -65,6 +66,9 @@
{cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
{keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
{cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
+ {user_lookup_fun, {fun(), InitialUserState::term()}} |
+ {psk_identity, string()} |
+ {srp_identity, {string(), string()}} |
{ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
{reuse_session, fun()} | {hibernate_after, integer()|undefined} |
{next_protocols_advertised, list(binary())} |
@@ -351,7 +355,7 @@ negotiated_next_protocol(#sslsocket{pid = Pid}) ->
ssl_connection:negotiated_next_protocol(Pid).
-spec cipher_suites() -> [erl_cipher_suite()].
--spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()].
+-spec cipher_suites(erlang | openssl | all ) -> [erl_cipher_suite()] | [string()].
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
@@ -364,8 +368,15 @@ cipher_suites(erlang) ->
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 <- ssl_cipher:suites(Version)];
+cipher_suites(all) ->
+ Version = ssl_record:highest_protocol_version([]),
+ Supported = ssl_cipher:suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites(),
+ [suite_definition(S) || S <- Supported].
%%--------------------------------------------------------------------
-spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
{ok, [gen_tcp:option()]} | {error, reason()}.
@@ -635,6 +646,9 @@ handle_options(Opts0, _Role) ->
cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
dh = handle_option(dh, Opts, undefined),
dhfile = handle_option(dhfile, Opts, undefined),
+ user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
+ psk_identity = handle_option(psk_identity, Opts, undefined),
+ srp_identity = handle_option(srp_identity, Opts, undefined),
ciphers = handle_option(ciphers, Opts, []),
%% Server side option
reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
@@ -654,7 +668,8 @@ handle_options(Opts0, _Role) ->
SslOptions = [versions, verify, verify_fun,
fail_if_no_peer_cert, verify_client_once,
depth, cert, certfile, key, keyfile,
- password, cacerts, cacertfile, dh, dhfile, ciphers,
+ password, cacerts, cacertfile, dh, dhfile,
+ user_lookup_fun, psk_identity, srp_identity, ciphers,
reuse_session, reuse_sessions, ssl_imp,
cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
erl_dist, next_protocols_advertised,
@@ -756,6 +771,20 @@ validate_option(dhfile, Value) when is_binary(Value) ->
Value;
validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
list_to_binary(Value);
+validate_option(psk_identity, undefined) ->
+ undefined;
+validate_option(psk_identity, Identity)
+ when is_list(Identity), Identity =/= "", length(Identity) =< 65535 ->
+ list_to_binary(Identity);
+validate_option(user_lookup_fun, undefined) ->
+ undefined;
+validate_option(user_lookup_fun, {Fun, _} = Value) when is_function(Fun, 3) ->
+ Value;
+validate_option(srp_identity, undefined) ->
+ undefined;
+validate_option(srp_identity, {Username, Password})
+ when is_list(Username), is_list(Password), Username =/= "", length(Username) =< 255 ->
+ {list_to_binary(Username), list_to_binary(Password)};
validate_option(ciphers, Value) when is_list(Value) ->
Version = ssl_record:highest_protocol_version([]),
try cipher_suites(Version, Value)
@@ -926,7 +955,10 @@ cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
cipher_suites(Version, Ciphers);
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites(),
+ Supported = 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
[] ->
Supported;
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 94e95d3cd3..1810043dfb 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -112,4 +112,6 @@ description_txt(?INTERNAL_ERROR) ->
description_txt(?USER_CANCELED) ->
"user canceled";
description_txt(?NO_RENEGOTIATION) ->
- "no renegotiation".
+ "no renegotiation";
+description_txt(?UNKNOWN_PSK_IDENTITY) ->
+ "unknown psk identity".
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 92548edab7..2a8a91aefa 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -60,6 +60,7 @@
%% internal_error(80),
%% user_canceled(90),
%% no_renegotiation(100),
+%% unknown_psk_identity(115),
%% (255)
%% } AlertDescription;
@@ -87,6 +88,7 @@
-define(INTERNAL_ERROR, 80).
-define(USER_CANCELED, 90).
-define(NO_RENEGOTIATION, 100).
+-define(UNKNOWN_PSK_IDENTITY, 115).
-define(ALERT_REC(Level,Desc), #alert{level=Level,description=Desc,where={?FILE, ?LINE}}).
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index d91e2a89a0..173c53709b 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -34,7 +34,7 @@
-export([security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
- suite/1, suites/1, anonymous_suites/0,
+ suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
openssl_suite/1, openssl_suite_name/1, filter/2,
hash_algorithm/1, sign_algorithm/1]).
@@ -215,6 +215,56 @@ anonymous_suites() ->
?TLS_DH_anon_WITH_AES_256_CBC_SHA256].
%%--------------------------------------------------------------------
+-spec psk_suites(tls_version()) -> [cipher_suite()].
+%%
+%% Description: Returns a list of the PSK cipher suites, only supported
+%% if explicitly set by user.
+%%--------------------------------------------------------------------
+psk_suites({3, N}) ->
+ psk_suites(N);
+
+psk_suites(N)
+ when N >= 3 ->
+ psk_suites(0) ++
+ [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256];
+
+psk_suites(_) ->
+ [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA,
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA,
+ ?TLS_PSK_WITH_RC4_128_SHA].
+
+%%--------------------------------------------------------------------
+-spec srp_suites() -> [cipher_suite()].
+%%
+%% Description: Returns a list of the SRP cipher suites, only supported
+%% if explicitly set by user.
+%%--------------------------------------------------------------------
+srp_suites() ->
+ [?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
+
+%%--------------------------------------------------------------------
-spec suite_definition(cipher_suite()) -> int_cipher_suite().
%%
%% Description: Return erlang cipher suite definition.
@@ -297,7 +347,84 @@ suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) ->
{dh_anon, aes_128_cbc, sha256, default_prf};
suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) ->
- {dh_anon, aes_256_cbc, sha256, default_prf}.
+ {dh_anon, aes_256_cbc, sha256, default_prf};
+
+%%% PSK Cipher Suites RFC 4279
+
+suite_definition(?TLS_PSK_WITH_RC4_128_SHA) ->
+ {psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ {psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ {psk, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_RC4_128_SHA) ->
+ {dhe_psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {dhe_psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) ->
+ {dhe_psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) ->
+ {dhe_psk, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_RC4_128_SHA) ->
+ {rsa_psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {rsa_psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) ->
+ {rsa_psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) ->
+ {rsa_psk, aes_256_cbc, sha, default_prf};
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA256) ->
+ {psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA384) ->
+ {psk, aes_256_cbc, sha384, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) ->
+ {dhe_psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) ->
+ {dhe_psk, aes_256_cbc, sha384, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) ->
+ {rsa_psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) ->
+ {rsa_psk, aes_256_cbc, sha384, default_prf};
+
+suite_definition(?TLS_PSK_WITH_NULL_SHA256) ->
+ {psk, null, sha256, default_prf};
+suite_definition(?TLS_PSK_WITH_NULL_SHA384) ->
+ {psk, null, sha384, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA256) ->
+ {dhe_psk, null, sha256, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) ->
+ {dhe_psk, null, sha384, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA256) ->
+ {rsa_psk, null, sha256, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA384) ->
+ {rsa_psk, null, sha384, default_prf};
+
+%%% SRP Cipher Suites RFC 5054
+
+suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_anon, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_dss, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) ->
+ {srp_anon, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ {srp_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ {srp_dss, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
+ {srp_anon, aes_256_cbc, sha, default_prf};
+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}.
+
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -370,7 +497,83 @@ suite({dhe_rsa, aes_256_cbc, sha256}) ->
suite({dh_anon, aes_128_cbc, sha256}) ->
?TLS_DH_anon_WITH_AES_128_CBC_SHA256;
suite({dh_anon, aes_256_cbc, sha256}) ->
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256.
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256;
+
+%%% PSK Cipher Suites RFC 4279
+
+suite({psk, rc4_128,sha}) ->
+ ?TLS_PSK_WITH_RC4_128_SHA;
+suite({psk, '3des_ede_cbc',sha}) ->
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({psk, aes_128_cbc,sha}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA;
+suite({psk, aes_256_cbc,sha}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA;
+suite({dhe_psk, rc4_128,sha}) ->
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA;
+suite({dhe_psk, '3des_ede_cbc',sha}) ->
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({dhe_psk, aes_128_cbc,sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+suite({dhe_psk, aes_256_cbc,sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+suite({rsa_psk, rc4_128,sha}) ->
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA;
+suite({rsa_psk, '3des_ede_cbc',sha}) ->
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({rsa_psk, aes_128_cbc,sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+suite({rsa_psk, aes_256_cbc,sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+suite({psk, aes_128_cbc, sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256;
+suite({psk, aes_256_cbc, sha384}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384;
+suite({dhe_psk, aes_128_cbc, sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
+suite({dhe_psk, aes_256_cbc, sha384}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
+suite({rsa_psk, aes_128_cbc, sha256}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256;
+suite({rsa_psk, aes_256_cbc, sha384}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384;
+
+suite({psk, null, sha256}) ->
+ ?TLS_PSK_WITH_NULL_SHA256;
+suite({psk, null, sha384}) ->
+ ?TLS_PSK_WITH_NULL_SHA384;
+suite({dhe_psk, null, sha256}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA256;
+suite({dhe_psk, null, sha384}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA384;
+suite({rsa_psk, null, sha256}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA256;
+suite({rsa_psk, null, sha384}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA384;
+
+%%% SRP Cipher Suites RFC 5054
+
+suite({srp_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
+suite({srp_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({srp_dss, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+suite({srp_anon, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
+suite({srp_rsa, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+suite({srp_dss, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+suite({srp_anon, aes_256_cbc, sha}) ->
+ ?TLS_SRP_SHA_WITH_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.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -415,7 +618,24 @@ openssl_suite("RC4-MD5") ->
openssl_suite("EDH-RSA-DES-CBC-SHA") ->
?TLS_DHE_RSA_WITH_DES_CBC_SHA;
openssl_suite("DES-CBC-SHA") ->
- ?TLS_RSA_WITH_DES_CBC_SHA.
+ ?TLS_RSA_WITH_DES_CBC_SHA;
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite("SRP-DSS-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-RSA-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-DSS-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_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.
+
+
%%--------------------------------------------------------------------
-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
%%
@@ -469,6 +689,33 @@ openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
"DHE-DSS-AES256-SHA256";
openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
"DHE-RSA-AES256-SHA256";
+
+%%% PSK Cipher Suites RFC 4279
+
+openssl_suite_name(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ "PSK-AES256-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ "PSK-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ "PSK-AES128-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_RC4_128_SHA) ->
+ "PSK-RC4-SHA";
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-RSA-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-DSS-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ "SRP-RSA-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ "SRP-DSS-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
+ "SRP-RSA-AES-256-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
+ "SRP-DSS-AES-256-CBC-SHA";
+
%% No oppenssl name
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
@@ -605,14 +852,14 @@ hash_size(md5) ->
16;
hash_size(sha) ->
20;
+hash_size(sha224) ->
+ 28;
hash_size(sha256) ->
- 32.
-%% Currently no supported cipher suites defaults to sha384 or sha512
-%% so these clauses are not needed at the moment.
-%% hash_size(sha384) ->
-%% 48;
-%% hash_size(sha512) ->
-%% 64.
+ 32;
+hash_size(sha384) ->
+ 48;
+hash_size(sha512) ->
+ 64.
%% RFC 5246: 6.2.3.2. CBC Block Cipher
%%
@@ -702,7 +949,8 @@ next_iv(Bin, IV) ->
NextIV.
rsa_signed_suites() ->
- dhe_rsa_suites() ++ rsa_suites().
+ dhe_rsa_suites() ++ rsa_suites() ++
+ psk_rsa_suites() ++ srp_rsa_suites().
dhe_rsa_suites() ->
[?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -712,6 +960,19 @@ dhe_rsa_suites() ->
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_DES_CBC_SHA].
+psk_rsa_suites() ->
+ [?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA].
+
+srp_rsa_suites() ->
+ [?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA].
+
rsa_suites() ->
[?TLS_RSA_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_256_CBC_SHA,
@@ -723,7 +984,7 @@ rsa_suites() ->
?TLS_RSA_WITH_DES_CBC_SHA].
dsa_signed_suites() ->
- dhe_dss_suites().
+ dhe_dss_suites() ++ srp_dss_suites().
dhe_dss_suites() ->
[?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
@@ -733,6 +994,11 @@ dhe_dss_suites() ->
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA].
+srp_dss_suites() ->
+ [?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
+
filter_rsa(OtpCert, RsaCiphers) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions,
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 0f439f8ed5..90d3704efd 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -250,4 +250,109 @@
%% hello extension data as they should.
-define(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, <<?BYTE(16#00), ?BYTE(16#FF)>>).
+%%% PSK Cipher Suites RFC 4279
+
+%% TLS_PSK_WITH_RC4_128_SHA = { 0x00, 0x8A };
+-define(TLS_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8A)>>).
+
+%% TLS_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8B };
+-define(TLS_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8B)>>).
+
+%% TLS_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x8C };
+-define(TLS_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8C)>>).
+
+%% TLS_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x8D };
+-define(TLS_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8D)>>).
+
+%% TLS_DHE_PSK_WITH_RC4_128_SHA = { 0x00, 0x8E };
+-define(TLS_DHE_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8E)>>).
+
+%% TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8F };
+-define(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8F)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x90 };
+-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#90)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x91 };
+-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#91)>>).
+
+%% TLS_RSA_PSK_WITH_RC4_128_SHA = { 0x00, 0x92 };
+-define(TLS_RSA_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#92)>>).
+
+%% TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x93 };
+-define(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#93)>>).
+
+%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x94 };
+-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#94)>>).
+
+%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x95 };
+-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#95)>>).
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+%% TLS_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xAE};
+-define(TLS_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#AE)>>).
+
+%% TLS_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xAF};
+-define(TLS_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#AF)>>).
+
+%% TLS_PSK_WITH_NULL_SHA256 = {0x00,0xB0};
+-define(TLS_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B0)>>).
+
+%% TLS_PSK_WITH_NULL_SHA384 = {0x00,0xB1};
+-define(TLS_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B1)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB2};
+-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B2)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB3};
+-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B3)>>).
+
+%% TLS_DHE_PSK_WITH_NULL_SHA256 = {0x00,0xB4};
+-define(TLS_DHE_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B4)>>).
+
+%% TLS_DHE_PSK_WITH_NULL_SHA384 = {0x00,0xB5};
+-define(TLS_DHE_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B5)>>).
+
+%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB6};
+-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B6)>>).
+
+%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB7};
+-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B7)>>).
+
+%% TLS_RSA_PSK_WITH_NULL_SHA256 = {0x00,0xB8};
+-define(TLS_RSA_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B8)>>).
+
+%% TLS_RSA_PSK_WITH_NULL_SHA384 = {0x00,0xB9};
+-define(TLS_RSA_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B9)>>).
+
+%%% SRP Cipher Suites RFC 5054
+
+%% TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1A };
+-define(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1A)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1B };
+-define(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1B)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1C };
+-define(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1C)>>).
+
+%% TLS_SRP_SHA_WITH_AES_128_CBC_SHA = { 0xC0,0x1D };
+-define(TLS_SRP_SHA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1D)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = { 0xC0,0x1E };
+-define(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1E)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = { 0xC0,0x1F };
+-define(TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1F)>>).
+
+%% TLS_SRP_SHA_WITH_AES_256_CBC_SHA = { 0xC0,0x20 };
+-define(TLS_SRP_SHA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#20)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = { 0xC0,0x21 };
+-define(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#21)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = { 0xC0,0x22 };
+-define(TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#22)>>).
+
-endif. % -ifdef(ssl_cipher).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 4d29ecce7a..1843377582 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -34,6 +34,8 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
+-include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
%% Internal application API
@@ -80,6 +82,9 @@
private_key, % PKIX: #'RSAPrivateKey'{}
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
diffie_hellman_keys, % {PublicKey, PrivateKey}
+ psk_identity, % binary() - server psk identity hint
+ srp_params, % #srp_user{}
+ srp_keys, % {PublicKey, PrivateKey}
premaster_secret, %
file_ref_db, % ets()
cert_db_ref, % ref()
@@ -528,7 +533,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 == dh_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
#state{} = State1 ->
{Record, State} = next_record(State1),
@@ -545,6 +552,45 @@ certify(#certificate_request{}, State0) ->
{Record, State} = next_record(State0#state{client_certificate_requested = true}),
next_state(certify, certify, Record, State);
+%% PSK and RSA_PSK might bypass the Server-Key-Exchange
+certify(#server_hello_done{},
+ #state{session = #session{master_secret = undefined},
+ negotiated_version = Version,
+ psk_identity = PSKIdentity,
+ premaster_secret = undefined,
+ role = client,
+ key_algorithm = Alg} = State0)
+ when Alg == psk ->
+ case server_psk_master_secret(PSKIdentity, State0) of
+ #state{} = State ->
+ client_certify_and_key_exchange(State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify(#server_hello_done{},
+ #state{session = #session{master_secret = undefined},
+ ssl_options = SslOpts,
+ negotiated_version = Version,
+ psk_identity = PSKIdentity,
+ premaster_secret = undefined,
+ role = client,
+ key_algorithm = Alg} = State0)
+ when Alg == rsa_psk ->
+ case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ PremasterSecret = make_premaster_secret(Version, rsa),
+ Len = byte_size(PSK),
+ RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>,
+ State1 = State0#state{premaster_secret = PremasterSecret},
+ State = master_from_premaster_secret(RealPMS, State1),
+ client_certify_and_key_exchange(State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end;
+
%% Master secret was determined with help of server-key exchange msg
certify(#server_hello_done{},
#state{session = #session{master_secret = MasterSecret} = Session,
@@ -631,6 +677,60 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
next_state(certify, cipher, Record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_psk_identity{identity = ClientPSKIdentity},
+ #state{negotiated_version = Version} = State0) ->
+ case server_psk_master_secret(ClientPSKIdentity, 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_dhe_psk_identity{
+ identity = ClientPSKIdentity,
+ dh_public = ClientPublicDhKey},
+ #state{negotiated_version = Version,
+ 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
+ #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_rsa_psk_identity{
+ identity = PskIdentity,
+ exchange_keys =
+ #encrypted_premaster_secret{premaster_secret= EncPMS}},
+ #state{negotiated_version = Version,
+ private_key = Key} = State0) ->
+ PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
+ case server_rsa_psk_master_secret(PskIdentity, PremasterSecret, 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_srp_public{srp_a = ClientPublicKey},
+ #state{negotiated_version = Version,
+ srp_params =
+ #srp_user{prime = Prime,
+ verifier = Verifier}
+ } = State0) ->
+ case server_srp_master_secret(Verifier, Prime, ClientPublicKey, 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.
%%--------------------------------------------------------------------
@@ -1151,7 +1251,9 @@ init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHan
init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CertFile, client) ->
try
- [OwnCert] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
+ %% Ignoring potential proxy-certificates see:
+ %% http://dev.globus.org/wiki/Security/ProxyFileFormat
+ [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, OwnCert}
catch _Error:_Reason ->
{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, undefined}
@@ -1159,7 +1261,7 @@ init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHan
init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CertFile, server) ->
try
- [OwnCert] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
+ [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, OwnCert}
catch
_:Reason ->
@@ -1444,7 +1546,8 @@ server_hello_done(#state{transport_cb = Transport,
State#state{connection_states = ConnectionStates,
tls_handshake_history = Handshake}.
-certify_server(#state{key_algorithm = dh_anon} = State) ->
+certify_server(#state{key_algorithm = Algo} = State)
+ when Algo == dh_anon; Algo == psk; Algo == dhe_psk ->
State;
certify_server(#state{transport_cb = Transport,
@@ -1499,6 +1602,128 @@ key_exchange(#state{role = server, key_algorithm = Algo,
diffie_hellman_keys = Keys,
tls_handshake_history = Handshake};
+key_exchange(#state{role = server, key_algorithm = psk,
+ ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
+ State;
+key_exchange(#state{role = server, key_algorithm = psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = 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, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {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 = server, key_algorithm = dhe_psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State) ->
+ Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ 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,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ diffie_hellman_keys = Keys,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = server, key_algorithm = rsa_psk,
+ ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
+ State;
+key_exchange(#state{role = server, key_algorithm = rsa_psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = 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, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {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 = server, key_algorithm = Algo,
+ ssl_options = #ssl_options{user_lookup_fun = LookupFun},
+ hashsign_algorithm = HashSignAlgo,
+ session = #session{srp_username = Username},
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State)
+ when Algo == srp_dss;
+ Algo == srp_rsa;
+ Algo == srp_anon ->
+ SrpParams = handle_srp_identity(Username, LookupFun),
+ Keys = case generate_srp_server_keys(SrpParams, 0) of
+ Alert = #alert{} ->
+ throw(Alert);
+ Keys0 = {_,_} ->
+ Keys0
+ end,
+ 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, {srp, Keys, SrpParams,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ srp_params = SrpParams,
+ srp_keys = Keys,
+ tls_handshake_history = Handshake};
+
key_exchange(#state{role = client,
connection_states = ConnectionStates0,
key_algorithm = rsa,
@@ -1528,6 +1753,68 @@ key_exchange(#state{role = client,
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,
+ negotiated_version = Version,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = ssl_handshake:key_exchange(client, Version, {psk, SslOpts#ssl_options.psk_identity}),
+ {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 = dhe_psk,
+ negotiated_version = Version,
+ diffie_hellman_keys = {DhPubKey, _},
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = ssl_handshake:key_exchange(client, Version, {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}),
+ {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 = rsa_psk,
+ public_key_info = PublicKeyInfo,
+ negotiated_version = Version,
+ premaster_secret = PremasterSecret,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = rsa_psk_key_exchange(Version, SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo),
+ {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,
+ connection_states = ConnectionStates0,
+ key_algorithm = Algorithm,
+ negotiated_version = Version,
+ srp_keys = {ClientPubKey, _},
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State)
+ when Algorithm == srp_dss;
+ Algorithm == srp_rsa;
+ Algorithm == srp_anon ->
+ Msg = ssl_handshake:key_exchange(client, Version, {srp, ClientPubKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
tls_handshake_history = Handshake}.
rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
@@ -1546,6 +1833,22 @@ rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
rsa_key_exchange(_, _, _) ->
throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)).
+rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
+ when Algorithm == ?rsaEncryption;
+ Algorithm == ?md2WithRSAEncryption;
+ Algorithm == ?md5WithRSAEncryption;
+ Algorithm == ?sha1WithRSAEncryption;
+ Algorithm == ?sha224WithRSAEncryption;
+ Algorithm == ?sha256WithRSAEncryption;
+ Algorithm == ?sha384WithRSAEncryption;
+ Algorithm == ?sha512WithRSAEncryption
+ ->
+ ssl_handshake:key_exchange(client, Version,
+ {psk_premaster_secret, PskIdentity, PremasterSecret,
+ PublicKeyInfo});
+rsa_psk_key_exchange(_, _, _, _) ->
+ throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)).
+
request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer},
connection_states = ConnectionStates0,
cert_db = CertDbHandle,
@@ -1664,7 +1967,23 @@ verify_server_key(#server_key_params{params = Params,
server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey},
State) ->
- dh_master_secret(P, G, ServerPublicDhKey, undefined, State).
+ dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+
+server_master_secret(#server_psk_params{
+ hint = IdentityHint},
+ State) ->
+ %% store for later use
+ State#state{psk_identity = IdentityHint};
+
+server_master_secret(#server_dhe_psk_params{
+ hint = IdentityHint,
+ dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey}},
+ State) ->
+ dhe_psk_master_secret(IdentityHint, P, G, ServerPublicDhKey, undefined, State);
+
+server_master_secret(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B},
+ State) ->
+ client_srp_master_secret(G, N, S, B, undefined, State).
master_from_premaster_secret(PremasterSecret,
#state{session = Session,
@@ -1694,6 +2013,131 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
[PMpint, GMpint]),
master_from_premaster_secret(PremasterSecret, State).
+handle_psk_identity(_PSKIdentity, LookupFun)
+ when LookupFun == undefined ->
+ error;
+handle_psk_identity(PSKIdentity, {Fun, UserState}) ->
+ Fun(psk, PSKIdentity, UserState).
+
+server_psk_master_secret(ClientPSKIdentity,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(ClientPSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ Len = byte_size(PSK),
+ PremasterSecret = <<?UINT16(Len), 0:(Len*8), ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(PremasterSecret, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ 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,
+ State#state{diffie_hellman_keys = Keys});
+
+dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, 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]),
+ DHLen = erlang:byte_size(DHSecret),
+ Len = erlang:byte_size(PSK),
+ PremasterSecret = <<?UINT16(DHLen), DHSecret/binary, ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(PremasterSecret, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+server_rsa_psk_master_secret(PskIdentity, PremasterSecret,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(PskIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ Len = byte_size(PSK),
+ RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(RealPMS, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+generate_srp_server_keys(_SrpParams, 10) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+generate_srp_server_keys(SrpParams =
+ #srp_user{generator = Generator, prime = Prime,
+ verifier = Verifier}, N) ->
+ case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of
+ error ->
+ generate_srp_server_keys(SrpParams, N+1);
+ Keys ->
+ Keys
+ end.
+
+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
+ error ->
+ generate_srp_client_keys(Generator, Prime, N+1);
+ Keys ->
+ Keys
+ end.
+
+handle_srp_identity(Username, {Fun, UserState}) ->
+ case Fun(srp, Username, UserState) of
+ {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),
+ #srp_user{generator = Generator, prime = Prime,
+ salt = Salt, verifier = Verifier};
+ #alert{} = Alert ->
+ throw(Alert);
+ _ ->
+ 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
+ error ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ PremasterSecret ->
+ master_from_premaster_secret(PremasterSecret, State)
+ end.
+
+client_srp_master_secret(_Generator, _Prime, _Salt, _ServerPub, #alert{} = Alert, _State) ->
+ Alert;
+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) ->
+ 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
+ error ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ PremasterSecret ->
+ master_from_premaster_secret(PremasterSecret, State)
+ end;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
next_state_connection(cipher, ack_connection(State#state{session = Session,
@@ -2493,19 +2937,26 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange)
when Major == 3 andalso Minor >= 3 andalso
(KeyExchange == rsa orelse
KeyExchange == dhe_rsa orelse
- KeyExchange == dh_rsa) ->
+ KeyExchange == dh_rsa orelse
+ KeyExchange == srp_rsa) ->
{sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == rsa;
KeyExchange == dhe_rsa;
- KeyExchange == dh_rsa ->
+ KeyExchange == dh_rsa;
+ KeyExchange == srp_rsa ->
{md5sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == dhe_dss;
- KeyExchange == dh_dss ->
+ KeyExchange == dh_dss;
+ KeyExchange == srp_dss ->
{sha, dsa};
default_hashsign(_Version, KeyExchange)
- when KeyExchange == dh_anon ->
+ when KeyExchange == dh_anon;
+ KeyExchange == psk;
+ KeyExchange == dhe_psk;
+ KeyExchange == rsa_psk;
+ KeyExchange == srp_anon ->
{null, anon}.
start_or_recv_cancel_timer(infinity, _RecvFrom) ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 889d310ca8..83c0092de2 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -28,6 +28,7 @@
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([master_secret/4, client_hello/8, server_hello/5, hello/4,
@@ -65,6 +66,7 @@ client_hello(Host, Port, ConnectionStates,
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
+ SRP = srp_user(SslOpts),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -76,6 +78,7 @@ client_hello(Host, Port, ConnectionStates,
renegotiation_info =
renegotiation_info(client, ConnectionStates, Renegotiation),
+ srp = SRP,
hash_signs = default_hash_signs(),
next_protocol_negotiation =
encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation)
@@ -162,7 +165,8 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
hello(#client_hello{client_version = ClientVersion, random = Random,
cipher_suites = CipherSuites,
- renegotiation_info = Info} = Hello,
+ renegotiation_info = Info,
+ srp = SRP} = Hello,
#ssl_options{versions = Versions,
secure_renegotiate = SecureRenegotation} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
@@ -171,13 +175,14 @@ hello(#client_hello{client_version = ClientVersion, random = Random,
case ssl_record:is_acceptable_version(Version, Versions) of
true ->
{Type, #session{cipher_suite = CipherSuite,
- compression_method = Compression} = Session}
+ compression_method = Compression} = 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
@@ -372,6 +377,10 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
{premaster_secret, binary(), public_key_info()} |
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
+ binary(), binary(), private_key()} |
+ {psk, binary()} |
+ {dhe_psk, binary(), binary()} |
+ {srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
binary(), binary(), private_key()}) ->
#client_key_exchange{} | #server_key_exchange{}.
%%
@@ -388,6 +397,33 @@ key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
dh_public = PublicKey}
};
+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>>}) ->
+ #client_key_exchange{
+ exchange_keys = #client_dhe_psk_identity{
+ identity = Identity,
+ dh_public = PublicKey}
+ };
+
+key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, PublicKey, _}}) ->
+ EncPremasterSecret =
+ encrypted_premaster_secret(Secret, PublicKey),
+ #client_key_exchange{
+ exchange_keys = #client_rsa_psk_identity{
+ identity = PskIdentity,
+ exchange_keys = EncPremasterSecret}};
+
+key_exchange(client, _Version, {srp, PublicKey}) ->
+ #client_key_exchange{
+ exchange_keys = #client_srp_public{
+ srp_a = PublicKey}
+ };
+
key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
#'DHParameter'{prime = P, base = G},
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
@@ -396,6 +432,34 @@ key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
ServerDHParams = #server_dh_params{dh_p = PBin,
dh_g = GBin, dh_y = PublicKey},
enc_server_key_exchange(Version, ServerDHParams, 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>>, _},
+ #'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}
+ },
+ enc_server_key_exchange(Version, ServerEDHPSKParams,
+ HashSign, ClientRandom, ServerRandom, PrivateKey);
+
+key_exchange(server, Version, {srp, {PublicKey, _},
+ #srp_user{generator = Generator, prime = Prime,
+ salt = Salt},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerSRPParams = #server_srp_params{srp_n = Prime, srp_g = Generator,
+ srp_s = Salt, srp_b = PublicKey},
+ enc_server_key_exchange(Version, ServerSRPParams, HashSign,
ClientRandom, ServerRandom, PrivateKey).
enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
@@ -525,7 +589,12 @@ get_tls_handshake(Version, Data, Buffer) ->
%%--------------------------------------------------------------------
-spec decode_client_key(binary(), key_algo(), tls_version()) ->
- #encrypted_premaster_secret{} | #client_diffie_hellman_public{}.
+ #encrypted_premaster_secret{}
+ | #client_diffie_hellman_public{}
+ | #client_psk_identity{}
+ | #client_dhe_psk_identity{}
+ | #client_rsa_psk_identity{}
+ | #client_srp_public{}.
%%
%% Description: Decode client_key data and return appropriate type
%%--------------------------------------------------------------------
@@ -677,6 +746,11 @@ cipher_suites(Suites, false) ->
cipher_suites(Suites, true) ->
Suites.
+srp_user(#ssl_options{srp_identity = {UserName, _}}) ->
+ #srp{username = UserName};
+srp_user(_) ->
+ undefined.
+
renegotiation_info(client, _, false) ->
#renegotiation_info{renegotiated_connection = undefined};
renegotiation_info(server, ConnectionStates, false) ->
@@ -759,6 +833,11 @@ 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}.
+
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
{ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
@@ -941,6 +1020,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
DecodedExtensions = dec_hello_extensions(Extensions),
RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined),
+ SRP = proplists:get_value(srp, DecodedExtensions, undefined),
HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined),
@@ -951,6 +1031,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suites = from_2bytes(CipherSuites),
compression_methods = Comp_methods,
renegotiation_info = RenegotiationInfo,
+ srp = SRP,
hash_signs = HashSigns,
next_protocol_negotiation = NextProtocolNegotiation
};
@@ -1029,7 +1110,23 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
- #client_diffie_hellman_public{dh_public = DH_Y}.
+ #client_diffie_hellman_public{dh_public = DH_Y};
+dec_client_key(<<?UINT16(Len), Id:Len/binary>>,
+ ?KEY_EXCHANGE_PSK, _) ->
+ #client_psk_identity{identity = Id};
+dec_client_key(<<?UINT16(Len), Id:Len/binary,
+ ?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_DHE_PSK, _) ->
+ #client_dhe_psk_identity{identity = Id, dh_public = DH_Y};
+dec_client_key(<<?UINT16(Len), Id:Len/binary, PKEPMS/binary>>,
+ ?KEY_EXCHANGE_RSA_PSK, {3, 0}) ->
+ #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}};
+dec_client_key(<<?UINT16(Len), Id:Len/binary, ?UINT16(_), PKEPMS/binary>>,
+ ?KEY_EXCHANGE_RSA_PSK, _) ->
+ #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}};
+dec_client_key(<<?UINT16(ALen), A:ALen/binary>>,
+ ?KEY_EXCHANGE_SRP, _) ->
+ #client_srp_public{srp_a = A}.
dec_ske_params(Len, Keys, Version) ->
<<Params:Len/bytes, Signature/binary>> = Keys,
@@ -1064,6 +1161,41 @@ dec_server_key(<<?UINT16(PLen), P:PLen/binary,
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 ->
+ Params = #server_psk_params{
+ hint = PskIdentityHint},
+ {BinMsg, HashSign, Signature} = dec_ske_params(Len + 2, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(<<?UINT16(Len), IdentityHint:Len/binary,
+ ?UINT16(PLen), P:PLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?UINT16(YLen), Y:YLen/binary, _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_DHE_PSK, Version) ->
+ DHParams = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y},
+ Params = #server_dhe_psk_params{
+ hint = IdentityHint,
+ dh_params = DHParams},
+ {BinMsg, HashSign, Signature} = dec_ske_params(Len + PLen + GLen + YLen + 8, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(<<?UINT16(NLen), N:NLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?BYTE(SLen), S:SLen/binary,
+ ?UINT16(BLen), B:BLen/binary, _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_SRP, Version) ->
+ Params = #server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B},
+ {BinMsg, HashSign, Signature} = dec_ske_params(NLen + GLen + SLen + BLen + 7, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
dec_server_key(_, _, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
@@ -1091,6 +1223,11 @@ dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binar
dec_hello_extensions(Rest, [{renegotiation_info,
#renegotiation_info{renegotiated_connection = RenegotiateInfo}} | Acc]);
+dec_hello_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), SRP:SRPLen/binary, Rest/binary>>, Acc)
+ when Len == SRPLen + 2 ->
+ dec_hello_extensions(Rest, [{srp,
+ #srp{username = SRP}} | Acc]);
+
dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
SignAlgoListLen = Len - 2,
@@ -1148,6 +1285,7 @@ enc_hs(#client_hello{client_version = {Major, Minor},
cipher_suites = CipherSuites,
compression_methods = CompMethods,
renegotiation_info = RenegotiationInfo,
+ srp = SRP,
hash_signs = HashSigns,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SIDLength = byte_size(SessionID),
@@ -1155,7 +1293,7 @@ enc_hs(#client_hello{client_version = {Major, Minor},
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- Extensions0 = hello_extensions(RenegotiationInfo, NextProtocolNegotiation),
+ Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation),
Extensions1 = if
Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns);
true -> Extensions0
@@ -1231,13 +1369,56 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) ->
<<?UINT16(PKEPMSLen), PKEPMS/binary>>;
enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
- <<?UINT16(Len), DHPublic/binary>>.
+ <<?UINT16(Len), DHPublic/binary>>;
+enc_cke(#client_psk_identity{identity = undefined}, _) ->
+ Id = <<"psk_identity">>,
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary>>;
+enc_cke(#client_psk_identity{identity = Id}, _) ->
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary>>;
+enc_cke(Identity = #client_dhe_psk_identity{identity = undefined}, Version) ->
+ enc_cke(Identity#client_dhe_psk_identity{identity = <<"psk_identity">>}, Version);
+enc_cke(#client_dhe_psk_identity{identity = Id, dh_public = DHPublic}, _) ->
+ Len = byte_size(Id),
+ DHLen = byte_size(DHPublic),
+ <<?UINT16(Len), Id/binary, ?UINT16(DHLen), DHPublic/binary>>;
+enc_cke(Identity = #client_rsa_psk_identity{identity = undefined}, Version) ->
+ enc_cke(Identity#client_rsa_psk_identity{identity = <<"psk_identity">>}, Version);
+enc_cke(#client_rsa_psk_identity{identity = Id, exchange_keys = ExchangeKeys}, Version) ->
+ EncPMS = enc_cke(ExchangeKeys, Version),
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary, EncPMS/binary>>;
+enc_cke(#client_srp_public{srp_a = A}, _) ->
+ Len = byte_size(A),
+ <<?UINT16(Len), A/binary>>.
enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
PLen = byte_size(P),
GLen = byte_size(G),
YLen = byte_size(Y),
- <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>.
+ <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_psk_params{hint = PskIdentityHint}) ->
+ Len = byte_size(PskIdentityHint),
+ <<?UINT16(Len), PskIdentityHint/binary>>;
+enc_server_key(Params = #server_dhe_psk_params{hint = undefined}) ->
+ enc_server_key(Params#server_dhe_psk_params{hint = <<>>});
+enc_server_key(#server_dhe_psk_params{
+ hint = PskIdentityHint,
+ dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y}}) ->
+ Len = byte_size(PskIdentityHint),
+ PLen = byte_size(P),
+ GLen = byte_size(G),
+ YLen = byte_size(Y),
+ <<?UINT16(Len), PskIdentityHint/binary,
+ ?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B}) ->
+ NLen = byte_size(N),
+ GLen = byte_size(G),
+ SLen = byte_size(S),
+ BLen = byte_size(B),
+ <<?UINT16(NLen), N/binary, ?UINT16(GLen), G/binary,
+ ?BYTE(SLen), S/binary, ?UINT16(BLen), B/binary>>.
enc_sign({_, anon}, _Sign, _Version) ->
<<>>;
@@ -1253,13 +1434,20 @@ enc_sign(_HashSign, Sign, _Version) ->
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).
+
%% Renegotiation info
hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) ->
[];
hello_extensions(#renegotiation_info{} = Info) ->
[Info];
+hello_extensions(#srp{} = Info) ->
+ [Info];
hello_extensions(#hash_sign_algos{} = Info) ->
- [Info].
+ [Info];
+hello_extensions(undefined) ->
+ [].
next_protocol_extension(undefined) ->
[];
@@ -1286,6 +1474,11 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest
Len = InfoLen +1,
enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/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 >>,
@@ -1395,6 +1588,15 @@ 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(psk) ->
+ ?KEY_EXCHANGE_PSK;
+key_exchange_alg(dhe_psk) ->
+ ?KEY_EXCHANGE_DHE_PSK;
+key_exchange_alg(rsa_psk) ->
+ ?KEY_EXCHANGE_RSA_PSK;
+key_exchange_alg(Alg)
+ when Alg == srp_rsa; Alg == srp_dss; Alg == srp_anon ->
+ ?KEY_EXCHANGE_SRP;
key_exchange_alg(_) ->
?NULL.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 2414d5b666..1fbb88f5f6 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -48,6 +48,7 @@
compression_method,
cipher_suite,
master_secret,
+ srp_username,
is_resumable,
time_stamp
}).
@@ -99,6 +100,7 @@
cipher_suites, % cipher_suites<2..2^16-1>
compression_methods, % compression_methods<1..2^8-1>,
renegotiation_info,
+ srp, % srp username to send
hash_signs, % supported combinations of hashes/signature algos
next_protocol_negotiation = undefined % [binary()]
}).
@@ -128,6 +130,10 @@
-define(KEY_EXCHANGE_RSA, 0).
-define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1).
+-define(KEY_EXCHANGE_PSK, 2).
+-define(KEY_EXCHANGE_DHE_PSK, 3).
+-define(KEY_EXCHANGE_RSA_PSK, 4).
+-define(KEY_EXCHANGE_SRP, 5).
-record(server_rsa_params, {
rsa_modulus, %% opaque RSA_modulus<1..2^16-1>
@@ -139,7 +145,23 @@
dh_g, %% opaque DH_g<1..2^16-1>
dh_y %% opaque DH_Ys<1..2^16-1>
}).
-
+
+-record(server_psk_params, {
+ hint
+ }).
+
+-record(server_dhe_psk_params, {
+ hint,
+ dh_params
+ }).
+
+-record(server_srp_params, {
+ srp_n, %% opaque srp_N<1..2^16-1>
+ srp_g, %% opaque srp_g<1..2^16-1>
+ srp_s, %% opaque srp_s<1..2^8-1>
+ srp_b %% opaque srp_B<1..2^16-1>
+ }).
+
-record(server_key_exchange, {
exchange_keys
}).
@@ -209,6 +231,24 @@
dh_public
}).
+-record(client_psk_identity, {
+ identity
+ }).
+
+-record(client_dhe_psk_identity, {
+ identity,
+ dh_public
+ }).
+
+-record(client_rsa_psk_identity, {
+ identity,
+ exchange_keys
+ }).
+
+-record(client_srp_public, {
+ srp_a
+ }).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Certificate verify - RFC 4346 section 7.4.8
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -235,6 +275,15 @@
}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SRP RFC 5054 section 2.8.1.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-define(SRP_EXT, 12).
+
+-record(srp, {
+ username
+ }).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Signature Algorithms RFC 5746 section 7.4.1.4.1.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(SIGNATURE_ALGORITHMS_EXT, 13).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index ed0dc34adf..96a1c8e1ce 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -90,6 +90,9 @@
cacertfile, % file()
dh, % der_encoded()
dhfile, % file()
+ user_lookup_fun, % server option, fun to lookup the user
+ psk_identity, % binary
+ srp_identity, % client option {User, Password}
ciphers, %
%% Local policy for the server if it want's to reuse the session
%% or not. Defaluts to allways returning true.
diff --git a/lib/ssl/src/ssl_srp.hrl b/lib/ssl/src/ssl_srp.hrl
new file mode 100644
index 0000000000..ab2be33ab2
--- /dev/null
+++ b/lib/ssl/src/ssl_srp.hrl
@@ -0,0 +1,31 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2012. 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
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record definition for the TLS SRP protocol
+%% see RFC 5054
+%%----------------------------------------------------------------------
+
+-record(srp_user, {
+ generator :: binary(),
+ prime :: binary(),
+ salt :: binary(),
+ verifier :: binary()
+ }).
diff --git a/lib/ssl/src/ssl_srp_primes.erl b/lib/ssl/src/ssl_srp_primes.erl
new file mode 100644
index 0000000000..ca20a8d673
--- /dev/null
+++ b/lib/ssl/src/ssl_srp_primes.erl
@@ -0,0 +1,506 @@
+-module(ssl_srp_primes).
+
+-export([get_srp_params/1, check_srp_params/2]).
+
+-define(PRIME_1024, <<16#EE, 16#AF, 16#0A, 16#B9, 16#AD, 16#B3, 16#8D,
+ 16#D6, 16#9C, 16#33, 16#F8, 16#0A, 16#FA, 16#8F,
+ 16#C5, 16#E8, 16#60, 16#72, 16#61, 16#87, 16#75,
+ 16#FF, 16#3C, 16#0B, 16#9E, 16#A2, 16#31, 16#4C,
+ 16#9C, 16#25, 16#65, 16#76, 16#D6, 16#74, 16#DF,
+ 16#74, 16#96, 16#EA, 16#81, 16#D3, 16#38, 16#3B,
+ 16#48, 16#13, 16#D6, 16#92, 16#C6, 16#E0, 16#E0,
+ 16#D5, 16#D8, 16#E2, 16#50, 16#B9, 16#8B, 16#E4,
+ 16#8E, 16#49, 16#5C, 16#1D, 16#60, 16#89, 16#DA,
+ 16#D1, 16#5D, 16#C7, 16#D7, 16#B4, 16#61, 16#54,
+ 16#D6, 16#B6, 16#CE, 16#8E, 16#F4, 16#AD, 16#69,
+ 16#B1, 16#5D, 16#49, 16#82, 16#55, 16#9B, 16#29,
+ 16#7B, 16#CF, 16#18, 16#85, 16#C5, 16#29, 16#F5,
+ 16#66, 16#66, 16#0E, 16#57, 16#EC, 16#68, 16#ED,
+ 16#BC, 16#3C, 16#05, 16#72, 16#6C, 16#C0, 16#2F,
+ 16#D4, 16#CB, 16#F4, 16#97, 16#6E, 16#AA, 16#9A,
+ 16#FD, 16#51, 16#38, 16#FE, 16#83, 16#76, 16#43,
+ 16#5B, 16#9F, 16#C6, 16#1D, 16#2F, 16#C0, 16#EB,
+ 16#06, 16#E3>>).
+-define(GENERATOR_1024, <<2>>).
+
+
+-define(PRIME_1536, <<16#9D, 16#EF, 16#3C, 16#AF, 16#B9, 16#39, 16#27,
+ 16#7A, 16#B1, 16#F1, 16#2A, 16#86, 16#17, 16#A4,
+ 16#7B, 16#BB, 16#DB, 16#A5, 16#1D, 16#F4, 16#99,
+ 16#AC, 16#4C, 16#80, 16#BE, 16#EE, 16#A9, 16#61,
+ 16#4B, 16#19, 16#CC, 16#4D, 16#5F, 16#4F, 16#5F,
+ 16#55, 16#6E, 16#27, 16#CB, 16#DE, 16#51, 16#C6,
+ 16#A9, 16#4B, 16#E4, 16#60, 16#7A, 16#29, 16#15,
+ 16#58, 16#90, 16#3B, 16#A0, 16#D0, 16#F8, 16#43,
+ 16#80, 16#B6, 16#55, 16#BB, 16#9A, 16#22, 16#E8,
+ 16#DC, 16#DF, 16#02, 16#8A, 16#7C, 16#EC, 16#67,
+ 16#F0, 16#D0, 16#81, 16#34, 16#B1, 16#C8, 16#B9,
+ 16#79, 16#89, 16#14, 16#9B, 16#60, 16#9E, 16#0B,
+ 16#E3, 16#BA, 16#B6, 16#3D, 16#47, 16#54, 16#83,
+ 16#81, 16#DB, 16#C5, 16#B1, 16#FC, 16#76, 16#4E,
+ 16#3F, 16#4B, 16#53, 16#DD, 16#9D, 16#A1, 16#15,
+ 16#8B, 16#FD, 16#3E, 16#2B, 16#9C, 16#8C, 16#F5,
+ 16#6E, 16#DF, 16#01, 16#95, 16#39, 16#34, 16#96,
+ 16#27, 16#DB, 16#2F, 16#D5, 16#3D, 16#24, 16#B7,
+ 16#C4, 16#86, 16#65, 16#77, 16#2E, 16#43, 16#7D,
+ 16#6C, 16#7F, 16#8C, 16#E4, 16#42, 16#73, 16#4A,
+ 16#F7, 16#CC, 16#B7, 16#AE, 16#83, 16#7C, 16#26,
+ 16#4A, 16#E3, 16#A9, 16#BE, 16#B8, 16#7F, 16#8A,
+ 16#2F, 16#E9, 16#B8, 16#B5, 16#29, 16#2E, 16#5A,
+ 16#02, 16#1F, 16#FF, 16#5E, 16#91, 16#47, 16#9E,
+ 16#8C, 16#E7, 16#A2, 16#8C, 16#24, 16#42, 16#C6,
+ 16#F3, 16#15, 16#18, 16#0F, 16#93, 16#49, 16#9A,
+ 16#23, 16#4D, 16#CF, 16#76, 16#E3, 16#FE, 16#D1,
+ 16#35, 16#F9, 16#BB>>).
+-define(GENERATOR_1536, <<2>>).
+
+-define(PRIME_2048, <<16#AC, 16#6B, 16#DB, 16#41, 16#32, 16#4A, 16#9A,
+ 16#9B, 16#F1, 16#66, 16#DE, 16#5E, 16#13, 16#89,
+ 16#58, 16#2F, 16#AF, 16#72, 16#B6, 16#65, 16#19,
+ 16#87, 16#EE, 16#07, 16#FC, 16#31, 16#92, 16#94,
+ 16#3D, 16#B5, 16#60, 16#50, 16#A3, 16#73, 16#29,
+ 16#CB, 16#B4, 16#A0, 16#99, 16#ED, 16#81, 16#93,
+ 16#E0, 16#75, 16#77, 16#67, 16#A1, 16#3D, 16#D5,
+ 16#23, 16#12, 16#AB, 16#4B, 16#03, 16#31, 16#0D,
+ 16#CD, 16#7F, 16#48, 16#A9, 16#DA, 16#04, 16#FD,
+ 16#50, 16#E8, 16#08, 16#39, 16#69, 16#ED, 16#B7,
+ 16#67, 16#B0, 16#CF, 16#60, 16#95, 16#17, 16#9A,
+ 16#16, 16#3A, 16#B3, 16#66, 16#1A, 16#05, 16#FB,
+ 16#D5, 16#FA, 16#AA, 16#E8, 16#29, 16#18, 16#A9,
+ 16#96, 16#2F, 16#0B, 16#93, 16#B8, 16#55, 16#F9,
+ 16#79, 16#93, 16#EC, 16#97, 16#5E, 16#EA, 16#A8,
+ 16#0D, 16#74, 16#0A, 16#DB, 16#F4, 16#FF, 16#74,
+ 16#73, 16#59, 16#D0, 16#41, 16#D5, 16#C3, 16#3E,
+ 16#A7, 16#1D, 16#28, 16#1E, 16#44, 16#6B, 16#14,
+ 16#77, 16#3B, 16#CA, 16#97, 16#B4, 16#3A, 16#23,
+ 16#FB, 16#80, 16#16, 16#76, 16#BD, 16#20, 16#7A,
+ 16#43, 16#6C, 16#64, 16#81, 16#F1, 16#D2, 16#B9,
+ 16#07, 16#87, 16#17, 16#46, 16#1A, 16#5B, 16#9D,
+ 16#32, 16#E6, 16#88, 16#F8, 16#77, 16#48, 16#54,
+ 16#45, 16#23, 16#B5, 16#24, 16#B0, 16#D5, 16#7D,
+ 16#5E, 16#A7, 16#7A, 16#27, 16#75, 16#D2, 16#EC,
+ 16#FA, 16#03, 16#2C, 16#FB, 16#DB, 16#F5, 16#2F,
+ 16#B3, 16#78, 16#61, 16#60, 16#27, 16#90, 16#04,
+ 16#E5, 16#7A, 16#E6, 16#AF, 16#87, 16#4E, 16#73,
+ 16#03, 16#CE, 16#53, 16#29, 16#9C, 16#CC, 16#04,
+ 16#1C, 16#7B, 16#C3, 16#08, 16#D8, 16#2A, 16#56,
+ 16#98, 16#F3, 16#A8, 16#D0, 16#C3, 16#82, 16#71,
+ 16#AE, 16#35, 16#F8, 16#E9, 16#DB, 16#FB, 16#B6,
+ 16#94, 16#B5, 16#C8, 16#03, 16#D8, 16#9F, 16#7A,
+ 16#E4, 16#35, 16#DE, 16#23, 16#6D, 16#52, 16#5F,
+ 16#54, 16#75, 16#9B, 16#65, 16#E3, 16#72, 16#FC,
+ 16#D6, 16#8E, 16#F2, 16#0F, 16#A7, 16#11, 16#1F,
+ 16#9E, 16#4A, 16#FF, 16#73>>).
+-define(GENERATOR_2048, <<2>>).
+
+-define(PRIME_3072, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#3A, 16#D2, 16#CA, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>).
+-define(GENERATOR_3072, <<5>>).
+
+-define(PRIME_4096, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#06, 16#31, 16#99,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF>>).
+-define(GENERATOR_4096, <<5>>).
+
+-define(PRIME_6144, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92,
+ 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70,
+ 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26,
+ 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D,
+ 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06,
+ 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38,
+ 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A,
+ 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17,
+ 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18,
+ 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14,
+ 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4,
+ 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6,
+ 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51,
+ 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4,
+ 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83,
+ 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0,
+ 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03,
+ 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE,
+ 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98,
+ 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90,
+ 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F,
+ 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A,
+ 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D,
+ 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B,
+ 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA,
+ 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1,
+ 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80,
+ 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2,
+ 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B,
+ 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA,
+ 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19,
+ 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA,
+ 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32,
+ 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04,
+ 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48,
+ 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B,
+ 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E,
+ 16#6D, 16#CC, 16#40, 16#24, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>).
+-define(GENERATOR_6144, <<5>>).
+
+-define(PRIME_8192, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92,
+ 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70,
+ 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26,
+ 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D,
+ 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06,
+ 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38,
+ 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A,
+ 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17,
+ 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18,
+ 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14,
+ 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4,
+ 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6,
+ 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51,
+ 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4,
+ 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83,
+ 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0,
+ 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03,
+ 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE,
+ 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98,
+ 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90,
+ 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F,
+ 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A,
+ 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D,
+ 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B,
+ 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA,
+ 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1,
+ 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80,
+ 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2,
+ 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B,
+ 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA,
+ 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19,
+ 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA,
+ 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32,
+ 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04,
+ 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48,
+ 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B,
+ 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E,
+ 16#6D, 16#BE, 16#11, 16#59, 16#74, 16#A3, 16#92,
+ 16#6F, 16#12, 16#FE, 16#E5, 16#E4, 16#38, 16#77,
+ 16#7C, 16#B6, 16#A9, 16#32, 16#DF, 16#8C, 16#D8,
+ 16#BE, 16#C4, 16#D0, 16#73, 16#B9, 16#31, 16#BA,
+ 16#3B, 16#C8, 16#32, 16#B6, 16#8D, 16#9D, 16#D3,
+ 16#00, 16#74, 16#1F, 16#A7, 16#BF, 16#8A, 16#FC,
+ 16#47, 16#ED, 16#25, 16#76, 16#F6, 16#93, 16#6B,
+ 16#A4, 16#24, 16#66, 16#3A, 16#AB, 16#63, 16#9C,
+ 16#5A, 16#E4, 16#F5, 16#68, 16#34, 16#23, 16#B4,
+ 16#74, 16#2B, 16#F1, 16#C9, 16#78, 16#23, 16#8F,
+ 16#16, 16#CB, 16#E3, 16#9D, 16#65, 16#2D, 16#E3,
+ 16#FD, 16#B8, 16#BE, 16#FC, 16#84, 16#8A, 16#D9,
+ 16#22, 16#22, 16#2E, 16#04, 16#A4, 16#03, 16#7C,
+ 16#07, 16#13, 16#EB, 16#57, 16#A8, 16#1A, 16#23,
+ 16#F0, 16#C7, 16#34, 16#73, 16#FC, 16#64, 16#6C,
+ 16#EA, 16#30, 16#6B, 16#4B, 16#CB, 16#C8, 16#86,
+ 16#2F, 16#83, 16#85, 16#DD, 16#FA, 16#9D, 16#4B,
+ 16#7F, 16#A2, 16#C0, 16#87, 16#E8, 16#79, 16#68,
+ 16#33, 16#03, 16#ED, 16#5B, 16#DD, 16#3A, 16#06,
+ 16#2B, 16#3C, 16#F5, 16#B3, 16#A2, 16#78, 16#A6,
+ 16#6D, 16#2A, 16#13, 16#F8, 16#3F, 16#44, 16#F8,
+ 16#2D, 16#DF, 16#31, 16#0E, 16#E0, 16#74, 16#AB,
+ 16#6A, 16#36, 16#45, 16#97, 16#E8, 16#99, 16#A0,
+ 16#25, 16#5D, 16#C1, 16#64, 16#F3, 16#1C, 16#C5,
+ 16#08, 16#46, 16#85, 16#1D, 16#F9, 16#AB, 16#48,
+ 16#19, 16#5D, 16#ED, 16#7E, 16#A1, 16#B1, 16#D5,
+ 16#10, 16#BD, 16#7E, 16#E7, 16#4D, 16#73, 16#FA,
+ 16#F3, 16#6B, 16#C3, 16#1E, 16#CF, 16#A2, 16#68,
+ 16#35, 16#90, 16#46, 16#F4, 16#EB, 16#87, 16#9F,
+ 16#92, 16#40, 16#09, 16#43, 16#8B, 16#48, 16#1C,
+ 16#6C, 16#D7, 16#88, 16#9A, 16#00, 16#2E, 16#D5,
+ 16#EE, 16#38, 16#2B, 16#C9, 16#19, 16#0D, 16#A6,
+ 16#FC, 16#02, 16#6E, 16#47, 16#95, 16#58, 16#E4,
+ 16#47, 16#56, 16#77, 16#E9, 16#AA, 16#9E, 16#30,
+ 16#50, 16#E2, 16#76, 16#56, 16#94, 16#DF, 16#C8,
+ 16#1F, 16#56, 16#E8, 16#80, 16#B9, 16#6E, 16#71,
+ 16#60, 16#C9, 16#80, 16#DD, 16#98, 16#ED, 16#D3,
+ 16#DF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF>>).
+-define(GENERATOR_8192, <<19>>).
+
+get_srp_params(srp_1024) -> {?GENERATOR_1024, ?PRIME_1024};
+get_srp_params(srp_1536) -> {?GENERATOR_1536, ?PRIME_1536};
+get_srp_params(srp_2048) -> {?GENERATOR_2048, ?PRIME_2048};
+get_srp_params(srp_3072) -> {?GENERATOR_3072, ?PRIME_3072};
+get_srp_params(srp_4096) -> {?GENERATOR_4096, ?PRIME_4096};
+get_srp_params(srp_6144) -> {?GENERATOR_6144, ?PRIME_6144};
+get_srp_params(srp_8192) -> {?GENERATOR_8192, ?PRIME_8192}.
+
+check_srp_params(?GENERATOR_1024, ?PRIME_1024) -> ok;
+check_srp_params(?GENERATOR_1536, ?PRIME_1536) -> ok;
+check_srp_params(?GENERATOR_2048, ?PRIME_2048) -> ok;
+check_srp_params(?GENERATOR_3072, ?PRIME_3072) -> ok;
+check_srp_params(?GENERATOR_4096, ?PRIME_4096) -> ok;
+check_srp_params(?GENERATOR_6144, ?PRIME_6144) -> ok;
+check_srp_params(?GENERATOR_8192, ?PRIME_8192) -> ok;
+check_srp_params(_Generator, _Prime) ->
+ not_accepted.
diff --git a/lib/ssl/src/ssl_srp_primes.hrl b/lib/ssl/src/ssl_srp_primes.hrl
new file mode 100644
index 0000000000..4bd534efbf
--- /dev/null
+++ b/lib/ssl/src/ssl_srp_primes.hrl
@@ -0,0 +1 @@
+-type srp_parameters() :: srp_1024 | srp_1536 | srp_2048 | srp_3072 | srp_4096 | srp_6144 | srp_8192.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 6b8f226a77..5cedde5d27 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -154,6 +154,10 @@ cipher_tests() ->
ciphers_dsa_signed_certs,
ciphers_dsa_signed_certs_openssl_names,
anonymous_cipher_suites,
+ psk_cipher_suites,
+ psk_with_hint_cipher_suites,
+ srp_cipher_suites,
+ srp_dsa_cipher_suites,
default_reject_anonymous].
error_handling_tests()->
@@ -1575,7 +1579,34 @@ anonymous_cipher_suites(Config) when is_list(Config) ->
Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:anonymous_suites(),
run_suites(Ciphers, Version, Config, anonymous).
-
+%%-------------------------------------------------------------------
+psk_cipher_suites() ->
+ [{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}].
+psk_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_suites(),
+ run_suites(Ciphers, Version, Config, psk).
+%%-------------------------------------------------------------------
+psk_with_hint_cipher_suites()->
+ [{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}].
+psk_with_hint_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_suites(),
+ run_suites(Ciphers, Version, Config, psk_with_hint).
+%%-------------------------------------------------------------------
+srp_cipher_suites()->
+ [{doc, "Test the SRP ciphersuites"}].
+srp_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:srp_suites(),
+ run_suites(Ciphers, Version, Config, srp).
+%%-------------------------------------------------------------------
+srp_dsa_cipher_suites()->
+ [{doc, "Test the SRP DSA ciphersuites"}].
+srp_dsa_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:srp_dss_suites(),
+ run_suites(Ciphers, Version, Config, srp_dsa).
%%--------------------------------------------------------------------
default_reject_anonymous()->
[{doc,"Test that by default anonymous cipher suites are rejected "}].
@@ -3113,7 +3144,19 @@ run_suites(Ciphers, Version, Config, Type) ->
anonymous ->
%% No certs in opts!
{?config(client_opts, Config),
- ?config(server_anon, Config)}
+ ?config(server_anon, Config)};
+ psk ->
+ {?config(client_psk, Config),
+ ?config(server_psk, Config)};
+ psk_with_hint ->
+ {?config(client_psk, Config),
+ ?config(server_psk_hint, Config)};
+ srp ->
+ {?config(client_srp, Config),
+ ?config(server_srp, Config)};
+ srp_dsa ->
+ {?config(client_srp_dsa, Config),
+ ?config(server_srp_dsa, Config)}
end,
Result = lists:map(fun(Cipher) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 76b302b1cb..d655d7659e 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -281,6 +281,13 @@ wait_for_result(Pid, Msg) ->
%% Unexpected
end.
+user_lookup(psk, _Identity, UserState) ->
+ {ok, UserState};
+user_lookup(srp, Username, _UserState) ->
+ Salt = ssl:random_bytes(16),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, <<"secret">>])]),
+ {ok, {srp_1024, Salt, UserPassHash}}.
+
cert_options(Config) ->
ClientCaCertFile = filename:join([?config(priv_dir, Config),
"client", "cacerts.pem"]),
@@ -307,6 +314,7 @@ cert_options(Config) ->
"badcert.pem"]),
BadKeyFile = filename:join([?config(priv_dir, Config),
"badkey.pem"]),
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
[{client_opts, [{ssl_imp, new},{reuseaddr, true}]},
{client_verification_opts, [{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile},
@@ -319,6 +327,24 @@ cert_options(Config) ->
{server_opts, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
{server_anon, [{ssl_imp, new},{reuseaddr, true}, {ciphers, anonymous_suites()}]},
+ {client_psk, [{ssl_imp, new},{reuseaddr, true},
+ {psk_identity, "Test-User"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
+ {server_psk, [{ssl_imp, new},{reuseaddr, true},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_suites()}]},
+ {server_psk_hint, [{ssl_imp, new},{reuseaddr, true},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {psk_identity, "HINT"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_suites()}]},
+ {client_srp, [{ssl_imp, new},{reuseaddr, true},
+ {srp_identity, {"Test-User", "secret"}}]},
+ {server_srp, [{ssl_imp, new},{reuseaddr, true},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {user_lookup_fun, {fun user_lookup/3, undefined}},
+ {ciphers, srp_suites()}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -356,7 +382,16 @@ make_dsa_cert(Config) ->
{verify, verify_peer}]},
{client_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ClientCaCertFile},
- {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]},
+ {server_srp_dsa, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {user_lookup_fun, {fun user_lookup/3, undefined}},
+ {ciphers, srp_dss_suites()}]},
+ {client_srp_dsa, [{ssl_imp, new},{reuseaddr, true},
+ {srp_identity, {"Test-User", "secret"}},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config].
@@ -675,6 +710,33 @@ anonymous_suites() ->
{dh_anon, aes_128_cbc, sha},
{dh_anon, aes_256_cbc, sha}].
+psk_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}].
+
+srp_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}].
+
+srp_dss_suites() ->
+ [{srp_dss, '3des_ede_cbc', sha},
+ {srp_dss, aes_128_cbc, sha},
+ {srp_dss, aes_256_cbc, sha}].
+
pem_to_der(File) ->
{ok, PemBin} = file:read_file(File),
public_key:pem_decode(PemBin).
diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml
index bafc2e0746..56a7131821 100644
--- a/lib/stdlib/doc/src/erl_parse.xml
+++ b/lib/stdlib/doc/src/erl_parse.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -167,6 +167,23 @@
<p>Converts the Erlang data structure <c><anno>Data</anno></c> into an
abstract form of type <c><anno>AbsTerm</anno></c>.
This is the inverse of <c>normalise/1</c>.</p>
+ <p><c>erl_parse:abstract(T)</c> is equivalent to
+ <c>erl_parse:abstract(T, 0)</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="abstract" arity="2"/>
+ <fsummary>Convert an Erlang term into an abstract form</fsummary>
+ <desc>
+ <p>Converts the Erlang data structure <c><anno>Data</anno></c> into an
+ abstract form of type <c><anno>AbsTerm</anno></c>.</p>
+ <p>The <c><anno>Line</anno></c> option is the line that will
+ be assigned to each node of the abstract form.</p>
+ <p>The <c><anno>Encoding</anno></c> option is used for
+ selecting which integer lists will be considered
+ as strings. The default is to use the encoding returned by
+ <seealso marker="epp#default_encoding/0">
+ <c>epp:default_encoding/0</c></seealso></p>
</desc>
</func>
</funcs>
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index 073faf2df2..a177b80739 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -211,18 +211,87 @@
<p>Gets the status of the process.</p>
<p>The value of <c><anno>Misc</anno></c> varies for different types of
processes. For example, a <c>gen_server</c> process returns
- the callback module's state, and a <c>gen_fsm</c> process
- returns information such as its current state name. Callback
- modules for <c>gen_server</c> and <c>gen_fsm</c> can also
- customise the value of <c><anno>Misc</anno></c> by exporting
- a <c>format_status/2</c> function that contributes
- module-specific information;
- see <seealso marker="gen_server#Module:format_status/2">gen_server:format_status/2</seealso>
- and <seealso marker="gen_fsm#Module:format_status/2">gen_fsm:format_status/2</seealso>
+ the callback module's state, a <c>gen_fsm</c> process
+ returns information such as its current state name and state data,
+ and a <c>gen_event</c> process returns information about each of its
+ registered handlers. Callback modules for <c>gen_server</c>,
+ <c>gen_fsm</c>, and <c>gen_event</c> can also customise the value
+ of <c><anno>Misc</anno></c> by exporting a <c>format_status/2</c>
+ function that contributes module-specific information;
+ see <seealso marker="gen_server#Module:format_status/2">gen_server:format_status/2</seealso>,
+ <seealso marker="gen_fsm#Module:format_status/2">gen_fsm:format_status/2</seealso>, and
+ <seealso marker="gen_event#Module:format_status/2">gen_event:format_status/2</seealso>
for more details.</p>
</desc>
</func>
<func>
+ <name name="get_state" arity="1"/>
+ <name name="get_state" arity="2"/>
+ <fsummary>Get the state of the process</fsummary>
+ <desc>
+ <p>Gets the state of the process.</p>
+ <note>
+ <p>These functions are intended only to help with debugging. They are provided for
+ convenience, allowing developers to avoid having to create their own state extraction
+ functions and also avoid having to interactively extract state from the return values of
+ <c><seealso marker="get_status/1">get_status/1</seealso></c> or
+ <c><seealso marker="get_status/2">get_status/2</seealso></c> while debugging.</p>
+ </note>
+ <p>The value of <c><anno>State</anno></c> varies for different types of
+ processes. For a <c>gen_server</c> process, the returned <c><anno>State</anno></c>
+ is simply the callback module's state. For a <c>gen_fsm</c> process,
+ <c><anno>State</anno></c> is the tuple <c>{CurrentStateName, CurrentStateData}</c>.
+ For a <c>gen_event</c> process, <c><anno>State</anno></c> a list of tuples,
+ where each tuple corresponds to an event handler registered in the process and contains
+ <c>{Module, Id, HandlerState}</c>, where <c>Module</c> is the event handler's module name,
+ <c>Id</c> is the handler's ID (which is the value <c>false</c> if it was registered without
+ an ID), and <c>HandlerState</c> is the handler's state.</p>
+ <p>To obtain more information about a process, including its state, see
+ <seealso marker="get_status/1">get_status/1</seealso> and
+ <seealso marker="get_status/2">get_status/2</seealso>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="replace_state" arity="2"/>
+ <name name="replace_state" arity="3"/>
+ <fsummary>Replace the state of the process</fsummary>
+ <desc>
+ <p>Replaces the state of the process, and returns the new state.</p>
+ <note>
+ <p>These functions are intended only to help with debugging, and they should not be
+ be called from normal code. They are provided for convenience, allowing developers
+ to avoid having to create their own custom state replacement functions.</p>
+ </note>
+ <p>The <c><anno>StateFun</anno></c> function provides a new state for the process.
+ The <c><anno>State</anno></c> argument and <c><anno>NewState</anno></c> return value
+ of <c><anno>StateFun</anno></c> vary for different types of processes. For a
+ <c>gen_server</c> process, <c><anno>State</anno></c> is simply the callback module's
+ state, and <c><anno>NewState</anno></c> is a new instance of that state. For a
+ <c>gen_fsm</c> process, <c><anno>State</anno></c> is the tuple
+ <c>{CurrentStateName, CurrentStateData}</c>, and <c><anno>NewState</anno></c>
+ is a similar tuple that may contain a new state name, new state data, or both.
+ For a <c>gen_event</c> process, <c><anno>State</anno></c> is the tuple
+ <c>{Module, Id, HandlerState}</c> where <c>Module</c> is the event handler's module name,
+ <c>Id</c> is the handler's ID (which is the value <c>false</c> if it was registered without
+ an ID), and <c>HandlerState</c> is the handler's state. <c><anno>NewState</anno></c> is a
+ similar tuple where <c>Module</c> and <c>Id</c> shall have the same values as in
+ <c><anno>State</anno></c> but the value of <c>HandlerState</c> may be different. Returning
+ a <c><anno>NewState</anno></c> whose <c>Module</c> or <c>Id</c> values differ from those of
+ <c><anno>State</anno></c> will result in the event handler's state remaining unchanged. For a
+ <c>gen_event</c> process, <c><anno>StateFun</anno></c> is called once for each event handler
+ registered in the <c>gen_event</c> process.</p>
+ <p>If a <c><anno>StateFun</anno></c> function decides not to effect any change in process
+ state, then regardless of process type, it may simply return its <c><anno>State</anno></c>
+ argument.</p>
+ <p>If a <c><anno>StateFun</anno></c> function crashes or throws an exception, then
+ for <c>gen_server</c> and <c>gen_fsm</c> processes, the original state of the process is
+ unchanged. For <c>gen_event</c> processes, a crashing or failing <c><anno>StateFun</anno></c>
+ function means that only the state of the particular event handler it was working on when it
+ failed or crashed is unchanged; it can still succeed in changing the states of other event
+ handlers registered in the same <c>gen_event</c> process.</p>
+ </desc>
+ </func>
+ <func>
<name name="install" arity="2"/>
<name name="install" arity="3"/>
<fsummary>Install a debug function in the process</fsummary>
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 9ff25fcbc5..7145b0858f 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -887,6 +887,7 @@ abstract(T, Options) when is_list(Options) ->
abstract(T, Line, Encoding).
-define(UNICODE(C),
+ is_integer(C) andalso
(C >= 0 andalso C < 16#D800 orelse
C > 16#DFFF andalso C < 16#FFFE orelse
C > 16#FFFF andalso C =< 16#10FFFF)).
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index 3651f608bc..d988a4d8c7 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -338,6 +338,7 @@ string_thing(_) -> "string".
-define(DIGIT(C), C >= $0, C =< $9).
-define(CHAR(C), is_integer(C), C >= 0).
-define(UNICODE(C),
+ is_integer(C) andalso
(C >= 0 andalso C < 16#D800 orelse
C > 16#DFFF andalso C < 16#FFFE orelse
C > 16#FFFF andalso C =< 16#10FFFF)).
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index 2b8ba86909..bfebf29080 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -229,6 +229,24 @@ wake_hib(Parent, ServerName, MSL, Debug) ->
fetch_msg(Parent, ServerName, MSL, Debug, Hib) ->
receive
+ {system, From, get_state} ->
+ States = [{Mod,Id,State} || #handler{module=Mod, id=Id, state=State} <- MSL],
+ sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
+ {States, [ServerName, MSL, Hib]}, Hib);
+ {system, From, {replace_state, StateFun}} ->
+ {NMSL, NStates} =
+ lists:unzip([begin
+ Cur = {Mod,Id,State},
+ try
+ NState = {Mod,Id,NS} = StateFun(Cur),
+ {HS#handler{state=NS}, NState}
+ catch
+ _:_ ->
+ {HS, Cur}
+ end
+ end || #handler{module=Mod, id=Id, state=State}=HS <- MSL]),
+ sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
+ {NStates, [ServerName, NMSL, Hib]}, Hib);
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[ServerName, MSL, Hib],Hib);
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index e480e2ac11..d9411e58cf 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -422,6 +422,17 @@ wake_hib(Parent, Name, StateName, StateData, Mod, Debug) ->
decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, Debug, Hib) ->
case Msg of
+ {system, From, get_state} ->
+ Misc = [Name, StateName, StateData, Mod, Time],
+ sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
+ {{StateName, StateData}, Misc}, Hib);
+ {system, From, {replace_state, StateFun}} ->
+ State = {StateName, StateData},
+ NState = {NStateName, NStateData} = try StateFun(State)
+ catch _:_ -> State end,
+ NMisc = [Name, NStateName, NStateData, Mod, Time],
+ sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
+ {NState, NMisc}, Hib);
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, StateName, StateData, Mod, Time], Hib);
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 04308a51b7..9c4b95acf6 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -372,6 +372,13 @@ wake_hib(Parent, Name, State, Mod, Debug) ->
decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
case Msg of
+ {system, From, get_state} ->
+ sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
+ {State, [Name, State, Mod, Time]}, Hib);
+ {system, From, {replace_state, StateFun}} ->
+ NState = try StateFun(State) catch _:_ -> State end,
+ sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
+ {NState, [Name, NState, Mod, Time]}, Hib);
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, State, Mod, Time], Hib);
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index 2d6287814e..bffeb44179 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -21,6 +21,8 @@
%% External exports
-export([suspend/1, suspend/2, resume/1, resume/2,
get_status/1, get_status/2,
+ get_state/1, get_state/2,
+ replace_state/2, replace_state/3,
change_code/4, change_code/5,
log/2, log/3, trace/2, trace/3, statistics/2, statistics/3,
log_to_file/2, log_to_file/3, no_debug/1, no_debug/2,
@@ -97,6 +99,32 @@ get_status(Name) -> send_system_msg(Name, get_status).
| (Misc :: term()).
get_status(Name, Timeout) -> send_system_msg(Name, get_status, Timeout).
+-spec get_state(Name) -> State when
+ Name :: name(),
+ State :: term().
+get_state(Name) -> send_system_msg(Name, get_state).
+
+-spec get_state(Name, Timeout) -> State when
+ Name :: name(),
+ Timeout :: timeout(),
+ State :: term().
+get_state(Name, Timeout) -> send_system_msg(Name, get_state, Timeout).
+
+-spec replace_state(Name, StateFun) -> NewState when
+ Name :: name(),
+ StateFun :: fun((State :: term()) -> NewState :: term()),
+ NewState :: term().
+replace_state(Name, StateFun) ->
+ send_system_msg(Name, {replace_state, StateFun}).
+
+-spec replace_state(Name, StateFun, Timeout) -> NewState when
+ Name :: name(),
+ StateFun :: fun((State :: term()) -> NewState :: term()),
+ Timeout :: timeout(),
+ NewState :: term().
+replace_state(Name, StateFun, Timeout) ->
+ send_system_msg(Name, {replace_state, StateFun}, Timeout).
+
-spec change_code(Name, Module, OldVsn, Extra) -> 'ok' | {error, Reason} when
Name :: name(),
Module :: module(),
@@ -362,6 +390,10 @@ do_cmd(_, suspend, _Parent, _Mod, Debug, Misc) ->
{suspended, ok, Debug, Misc};
do_cmd(_, resume, _Parent, _Mod, Debug, Misc) ->
{running, ok, Debug, Misc};
+do_cmd(SysState, get_state, _Parent, _Mod, Debug, {State, Misc}) ->
+ {SysState, State, Debug, Misc};
+do_cmd(SysState, replace_state, _Parent, _Mod, Debug, {State, Misc}) ->
+ {SysState, State, Debug, Misc};
do_cmd(SysState, get_status, Parent, Mod, Debug, Misc) ->
Res = get_status(SysState, Parent, Mod, Debug, Misc),
{SysState, Res, Debug, Misc};
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
index ecd181e87c..361abbb771 100644
--- a/lib/stdlib/test/erl_scan_SUITE.erl
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -21,7 +21,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([ error_1/1, error_2/1, iso88591/1, otp_7810/1, otp_10302/1]).
+-export([ error_1/1, error_2/1, iso88591/1, otp_7810/1, otp_10302/1,
+ otp_10990/1, otp_10992/1]).
-import(lists, [nth/2,flatten/1]).
-import(io_lib, [print/1]).
@@ -60,7 +61,7 @@ end_per_testcase(_Case, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [{group, error}, iso88591, otp_7810, otp_10302].
+ [{group, error}, iso88591, otp_7810, otp_10302, otp_10990, otp_10992].
groups() ->
[{error, [], [error_1, error_2]}].
@@ -1121,6 +1122,29 @@ otp_10302(Config) when is_list(Config) ->
erl_parse:abstract("a"++[1024]++"c", [{encoding,latin1}]),
ok.
+otp_10990(doc) ->
+ "OTP-10990. Floating point number in input string.";
+otp_10990(suite) ->
+ [];
+otp_10990(Config) when is_list(Config) ->
+ {'EXIT',_} = (catch {foo, erl_scan:string([$",42.0,$"],1)}),
+ ok.
+
+otp_10992(doc) ->
+ "OTP-10992. List of floats to abstract format.";
+otp_10992(suite) ->
+ [];
+otp_10992(Config) when is_list(Config) ->
+ {cons,0,{float,0,42.0},{nil,0}} =
+ erl_parse:abstract([42.0], [{encoding,unicode}]),
+ {cons,0,{float,0,42.0},{nil,0}} =
+ erl_parse:abstract([42.0], [{encoding,utf8}]),
+ {cons,0,{integer,0,65},{cons,0,{float,0,42.0},{nil,0}}} =
+ erl_parse:abstract([$A,42.0], [{encoding,unicode}]),
+ {cons,0,{integer,0,65},{cons,0,{float,0,42.0},{nil,0}}} =
+ erl_parse:abstract([$A,42.0], [{encoding,utf8}]),
+ ok.
+
test_string(String, Expected) ->
{ok, Expected, _End} = erl_scan:string(String),
test(String).
diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl
index b6cdd0a9c7..eebfec3336 100644
--- a/lib/stdlib/test/escript_SUITE.erl
+++ b/lib/stdlib/test/escript_SUITE.erl
@@ -615,7 +615,7 @@ archive_script_file_access(Config) when is_list(Config) ->
%% 3. If symlinks are supported, run one of the scripts via a symlink.
%%
%% This is in order to test error b) described above this test case.
- case file:read_link(Symlink2) of
+ case element(1,os:type()) =:= win32 orelse file:read_link(Symlink2) of
{ok,_} ->
run(PrivDir, "./" ++ SymlinkName2 ++ " " ++ ScriptName2,
[<<"ExitCode:0">>]);
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl
index b03c8ba70d..523621e4f3 100644
--- a/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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
@@ -56,7 +56,7 @@ main([RelArchiveFile]) ->
%% If symlinks are supported on this platform...
RelSymlinkArchiveFile = "symlink_to_" ++ RelArchiveFile,
- case file:read_link(RelSymlinkArchiveFile) of
+ case element(1,os:type()) =:= win32 orelse file:read_link(RelSymlinkArchiveFile) of
{ok,_} ->
DotSlashSymlinkArchiveFile = "./" ++ RelSymlinkArchiveFile,
AbsSymlinkArchiveFile=filename:join(filename:dirname(AbsArchiveFile),
diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl
index 5c51e12e35..6be5a299b6 100644
--- a/lib/stdlib/test/gen_event_SUITE.erl
+++ b/lib/stdlib/test/gen_event_SUITE.erl
@@ -26,13 +26,14 @@
delete_handler/1, swap_handler/1, swap_sup_handler/1,
notify/1, sync_notify/1, call/1, info/1, hibernate/1,
call_format_status/1, call_format_status_anon/1,
- error_format_status/1]).
+ error_format_status/1, get_state/1, replace_state/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[start, {group, test_all}, hibernate,
- call_format_status, call_format_status_anon, error_format_status].
+ call_format_status, call_format_status_anon, error_format_status,
+ get_state, replace_state].
groups() ->
[{test_all, [],
@@ -956,3 +957,45 @@ error_format_status(Config) when is_list(Config) ->
?line ok = gen_event:stop(Pid),
process_flag(trap_exit, OldFl),
ok.
+
+get_state(suite) ->
+ [];
+get_state(doc) ->
+ ["Test that sys:get_state/1,2 return the gen_event state"];
+get_state(Config) when is_list(Config) ->
+ {ok, Pid} = gen_event:start({local, my_dummy_handler}),
+ State1 = self(),
+ ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State1]),
+ [{dummy1_h,false,State1}] = sys:get_state(Pid),
+ [{dummy1_h,false,State1}] = sys:get_state(Pid, 5000),
+ State2 = {?MODULE, self()},
+ ok = gen_event:add_handler(my_dummy_handler, {dummy1_h,id}, [State2]),
+ Result1 = sys:get_state(Pid),
+ [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result1),
+ Result2 = sys:get_state(Pid, 5000),
+ [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result2),
+ ok = gen_event:stop(Pid),
+ ok.
+
+replace_state(suite) ->
+ [];
+replace_state(doc) ->
+ ["Test that replace_state/2,3 replace the gen_event state"];
+replace_state(Config) when is_list(Config) ->
+ {ok, Pid} = gen_event:start({local, my_dummy_handler}),
+ State1 = self(),
+ ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State1]),
+ [{dummy1_h,false,State1}] = sys:get_state(Pid),
+ NState1 = "replaced",
+ Replace1 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState1) end,
+ [{dummy1_h,false,NState1}] = sys:replace_state(Pid, Replace1),
+ [{dummy1_h,false,NState1}] = sys:get_state(Pid),
+ NState2 = "replaced again",
+ Replace2 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState2) end,
+ [{dummy1_h,false,NState2}] = sys:replace_state(Pid, Replace2, 5000),
+ [{dummy1_h,false,NState2}] = sys:get_state(Pid),
+ %% verify no change in state if replace function crashes
+ Replace3 = fun(_) -> exit(fail) end,
+ [{dummy1_h,false,NState2}] = sys:replace_state(Pid, Replace3),
+ [{dummy1_h,false,NState2}] = sys:get_state(Pid),
+ ok.
diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl
index a637a8543b..fd15838b7d 100644
--- a/lib/stdlib/test/gen_fsm_SUITE.erl
+++ b/lib/stdlib/test/gen_fsm_SUITE.erl
@@ -31,7 +31,7 @@
-export([shutdown/1]).
--export([ sys1/1, call_format_status/1, error_format_status/1]).
+-export([ sys1/1, call_format_status/1, error_format_status/1, get_state/1, replace_state/1]).
-export([hibernate/1,hiber_idle/3,hiber_wakeup/3,hiber_idle/2,hiber_wakeup/2]).
@@ -66,7 +66,7 @@ groups() ->
start8, start9, start10, start11, start12]},
{abnormal, [], [abnormal1, abnormal2]},
{sys, [],
- [sys1, call_format_status, error_format_status]}].
+ [sys1, call_format_status, error_format_status, get_state, replace_state]}].
init_per_suite(Config) ->
Config.
@@ -413,6 +413,40 @@ error_format_status(Config) when is_list(Config) ->
process_flag(trap_exit, OldFl),
ok.
+get_state(Config) when is_list(Config) ->
+ State = self(),
+ {ok, Pid} = gen_fsm:start(?MODULE, {state_data, State}, []),
+ {idle, State} = sys:get_state(Pid),
+ {idle, State} = sys:get_state(Pid, 5000),
+ stop_it(Pid),
+
+ %% check that get_state can handle a name being an atom (pid is
+ %% already checked by the previous test)
+ {ok, Pid2} = gen_fsm:start({local, gfsm}, gen_fsm_SUITE, {state_data, State}, []),
+ {idle, State} = sys:get_state(gfsm),
+ {idle, State} = sys:get_state(gfsm, 5000),
+ stop_it(Pid2),
+ ok.
+
+replace_state(Config) when is_list(Config) ->
+ State = self(),
+ {ok, Pid} = gen_fsm:start(?MODULE, {state_data, State}, []),
+ {idle, State} = sys:get_state(Pid),
+ NState1 = "replaced",
+ Replace1 = fun({StateName, _}) -> {StateName, NState1} end,
+ {idle, NState1} = sys:replace_state(Pid, Replace1),
+ {idle, NState1} = sys:get_state(Pid),
+ NState2 = "replaced again",
+ Replace2 = fun({idle, _}) -> {state0, NState2} end,
+ {state0, NState2} = sys:replace_state(Pid, Replace2, 5000),
+ {state0, NState2} = sys:get_state(Pid),
+ %% verify no change in state if replace function crashes
+ Replace3 = fun(_) -> error(fail) end,
+ {state0, NState2} = sys:replace_state(Pid, Replace3),
+ {state0, NState2} = sys:get_state(Pid),
+ stop_it(Pid),
+ ok.
+
%% Hibernation
hibernate(suite) -> [];
hibernate(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index dffeadb423..3b6a3f38bc 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -32,7 +32,7 @@
spec_init_local_registered_parent/1,
spec_init_global_registered_parent/1,
otp_5854/1, hibernate/1, otp_7669/1, call_format_status/1,
- error_format_status/1, call_with_huge_message_queue/1
+ error_format_status/1, get_state/1, replace_state/1, call_with_huge_message_queue/1
]).
% spawn export
@@ -57,6 +57,7 @@ all() ->
spec_init_local_registered_parent,
spec_init_global_registered_parent, otp_5854, hibernate,
otp_7669, call_format_status, error_format_status,
+ get_state, replace_state,
call_with_huge_message_queue].
groups() ->
@@ -1033,6 +1034,51 @@ error_format_status(Config) when is_list(Config) ->
process_flag(trap_exit, OldFl),
ok.
+%% Verify that sys:get_state correctly returns gen_server state
+%%
+get_state(suite) ->
+ [];
+get_state(doc) ->
+ ["Test that sys:get_state/1,2 return the gen_server state"];
+get_state(Config) when is_list(Config) ->
+ State = self(),
+ {ok, _Pid} = gen_server:start_link({local, get_state},
+ ?MODULE, {state,State}, []),
+ State = sys:get_state(get_state),
+ State = sys:get_state(get_state, 5000),
+ {ok, Pid} = gen_server:start_link(?MODULE, {state,State}, []),
+ State = sys:get_state(Pid),
+ State = sys:get_state(Pid, 5000),
+ ok.
+
+%% Verify that sys:replace_state correctly replaces gen_server state
+%%
+replace_state(suite) ->
+ [];
+replace_state(doc) ->
+ ["Test that sys:replace_state/1,2 replace the gen_server state"];
+replace_state(Config) when is_list(Config) ->
+ State = self(),
+ {ok, _Pid} = gen_server:start_link({local, replace_state},
+ ?MODULE, {state,State}, []),
+ State = sys:get_state(replace_state),
+ NState1 = "replaced",
+ Replace1 = fun(_) -> NState1 end,
+ NState1 = sys:replace_state(replace_state, Replace1),
+ NState1 = sys:get_state(replace_state),
+ {ok, Pid} = gen_server:start_link(?MODULE, {state,NState1}, []),
+ NState1 = sys:get_state(Pid),
+ Suffix = " again",
+ NState2 = NState1 ++ Suffix,
+ Replace2 = fun(S) -> S ++ Suffix end,
+ NState2 = sys:replace_state(Pid, Replace2, 5000),
+ NState2 = sys:get_state(Pid, 5000),
+ %% verify no change in state if replace function crashes
+ Replace3 = fun(_) -> throw(fail) end,
+ NState2 = sys:replace_state(Pid, Replace3),
+ NState2 = sys:get_state(Pid, 5000),
+ ok.
+
%% Test that the time for a huge message queue is not
%% significantly slower than with an empty message queue.
call_with_huge_message_queue(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index e16ba55481..76a8109a8d 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -147,8 +147,7 @@ unicode_prompt(Config) when is_list(Config) ->
%% And one with oldshell
?line rtnode([{putline,""},
{putline, "2."},
- {getline_re, ".*2."},
- {getline, "2"},
+ {getline_re, ".*2$"},
{putline, "shell:prompt_func({io_proto_SUITE,uprompt})."},
{getline_re, ".*default"},
{putline, "io:get_line('')."},
@@ -263,8 +262,7 @@ setopts_getopts(Config) when is_list(Config) ->
%% And one with oldshell
?line rtnode([{putline,""},
{putline, "2."},
- {getline_re, ".*2."},
- {getline, "2"},
+ {getline_re, ".*2$"},
{putline, "lists:keyfind(binary,1,io:getopts())."},
{getline_re, ".*{binary,false}"},
{putline, "io:get_line('')."},
@@ -467,8 +465,7 @@ unicode_options(Config) when is_list(Config) ->
end,
?line rtnode([{putline,""},
{putline, "2."},
- {getline_re, ".*2."},
- {getline, "2"},
+ {getline_re, ".*2$"},
{putline, "lists:keyfind(encoding,1,io:getopts())."},
{getline_re, ".*{encoding,latin1}"},
{putline, "io:format(\"~ts~n\",[[1024]])."},
@@ -701,8 +698,7 @@ binary_options(Config) when is_list(Config) ->
old ->
ok;
new ->
- ?line rtnode([{putline,""},
- {putline, "2."},
+ ?line rtnode([{putline, "2."},
{getline, "2"},
{putline, "lists:keyfind(binary,1,io:getopts())."},
{getline, "{binary,false}"},
@@ -720,10 +716,8 @@ binary_options(Config) when is_list(Config) ->
],[])
end,
%% And one with oldshell
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline_re, ".*2."},
- {getline, "2"},
+ ?line rtnode([{putline, "2."},
+ {getline_re, ".*2$"},
{putline, "lists:keyfind(binary,1,io:getopts())."},
{getline_re, ".*{binary,false}"},
{putline, "io:get_line('')."},
diff --git a/lib/tools/emacs/erlang-start.el b/lib/tools/emacs/erlang-start.el
index bbcea3e46a..e1dc86621e 100644
--- a/lib/tools/emacs/erlang-start.el
+++ b/lib/tools/emacs/erlang-start.el
@@ -83,6 +83,7 @@
;; Associate files extensions ".erl" and ".hrl" with Erlang mode.
;;
+;;;###autoload
(let ((a '("\\.erl\\'" . erlang-mode))
(b '("\\.hrl\\'" . erlang-mode)))
(or (assoc (car a) auto-mode-alist)
@@ -94,6 +95,7 @@
;; Associate files using interpreter "escript" with Erlang mode.
;;
+;;;###autoload
(add-to-list 'interpreter-mode-alist (cons "escript" 'erlang-mode))
;;
@@ -101,6 +103,7 @@
;; file completion.
;;
+;;;###autoload
(let ((erl-ext '(".jam" ".vee" ".beam")))
(while erl-ext
(let ((cie completion-ignored-extensions))
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index dfcfc3675f..c2c627abe0 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -1139,9 +1139,14 @@ remote_collect(Module,Nodes,Stop) ->
do_collection(Node, Module, Stop) ->
CollectorPid = spawn(fun collector_proc/0),
- remote_call(Node,{remote,collect,Module,CollectorPid, self()}),
- if Stop -> remote_call(Node,{remote,stop});
- true -> ok
+ case remote_call(Node,{remote,collect,Module,CollectorPid, self()}) of
+ {error,node_dead} ->
+ CollectorPid ! done,
+ ok;
+ ok when Stop ->
+ remote_call(Node,{remote,stop});
+ ok ->
+ ok
end.
%% Process which receives chunks of data from remote nodes - either when
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index 5abc5c41b1..c033be98a3 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -27,7 +27,8 @@
dont_reconnect_after_stop/1, stop_node_after_disconnect/1,
export_import/1,
otp_5031/1, eif/1, otp_5305/1, otp_5418/1, otp_6115/1, otp_7095/1,
- otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1]).
+ otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1,
+ otp_10979_hanging_node/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -52,7 +53,7 @@ all() ->
dont_reconnect_after_stop, stop_node_after_disconnect,
export_import, otp_5031, eif, otp_5305, otp_5418,
otp_6115, otp_7095, otp_8188, otp_8270, otp_8273,
- otp_8340];
+ otp_8340, otp_10979_hanging_node];
_pid ->
{skip,
"It looks like the test server is running "
@@ -1381,6 +1382,25 @@ comprehension_8188(Cf) ->
ok.
+otp_10979_hanging_node(_Config) ->
+
+ P1 = processes(),
+
+ cover:stop(non_existing_node),
+ cover:stop(),
+
+ P2 = processes(),
+
+ case P2--P1 of
+ [] ->
+ ok;
+ New ->
+ [io:format("New: ~p, ~p~n",[P,process_info(P)]) || P<-New],
+ ct:fail(hanging_process)
+ end,
+
+ ok.
+
%%--Auxiliary------------------------------------------------------------
analyse_expr(Expr, Config) ->
diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl
index cf17818a9d..d55a037599 100644
--- a/lib/wx/test/wx_basic_SUITE.erl
+++ b/lib/wx/test/wx_basic_SUITE.erl
@@ -2,7 +2,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
@@ -100,6 +100,7 @@ several_apps(Config) ->
|| N <- lists:seq(1,4)],
process_flag(trap_exit,true),
?m_multi_receive([{complete,Pid} || Pid <- Pids]),
+ [Pid ! quit || Pid <- Pids],
case wx_test_lib:user_available(Config) of
true ->
receive {'EXIT',_,foo} -> ok end;
@@ -118,6 +119,7 @@ several_apps(Parent, N, Config) ->
#wx{obj=Frame, event=#wxSize{}} ->
Parent ! {complete, self()}
end,
+ receive quit -> ok end,
wx_test_lib:wx_destroy(Frame, Config),
exit(foo).
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index 4186d73c88..7c3eda0be1 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -140,7 +140,7 @@ treeCtrl(Config) ->
?m({true, {_,Y1,_,_}} when Y1 > Y0, wxTreeCtrl:getBoundingRect(Tree, Item2)),
?m({Item1, _}, wxTreeCtrl:hitTest(Tree, {X0+W0 div 2, Y0+H0 div 2})),
?m(true, wxTreeCtrl:isTreeItemIdOk(Item1)),
- ?m({0, _}, wxTreeCtrl:hitTest(Tree, {X0+W0 div 2, Y0+H0+H0})),
+ ?m({0, _}, wxTreeCtrl:hitTest(Tree, {X0+W0+W0, Y0+H0+4*H0})),
?m(false, wxTreeCtrl:isTreeItemIdOk(0)),
wxFrame:connect(Tree, command_tree_item_expanded),