aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--bootstrap/lib/compiler/ebin/beam_receive.beambin6616 -> 6480 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin37788 -> 37728 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_master.beambin6336 -> 6288 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log.beambin37112 -> 36988 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file.beambin14740 -> 14492 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_io_server.beambin14548 -> 14528 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_server.beambin5456 -> 5420 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_gethost_native.beambin10536 -> 10500 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/os.beambin5276 -> 5280 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/rpc.beambin8752 -> 8616 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/beam_lib.beambin18112 -> 18104 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets.beambin53604 -> 53544 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin27456 -> 27416 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen.beambin4080 -> 4048 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_event.beambin17608 -> 18264 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_fsm.beambin15360 -> 15628 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_server.beambin17264 -> 17404 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io.beambin6872 -> 6836 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/lists.beambin29592 -> 29636 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin7860 -> 10004 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor.beambin23084 -> 23544 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sys.beambin7332 -> 7556 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/timer.beambin5452 -> 5476 bytes
-rw-r--r--erts/configure.in16
-rw-r--r--erts/doc/src/crash_dump.xml4
-rw-r--r--erts/doc/src/erl.xml36
-rw-r--r--erts/doc/src/notes.xml23
-rw-r--r--erts/emulator/Makefile.in16
-rw-r--r--erts/emulator/beam/beam_load.c14
-rw-r--r--erts/emulator/beam/bif.tab6
-rw-r--r--erts/emulator/beam/big.c23
-rw-r--r--erts/emulator/beam/break.c3
-rw-r--r--erts/emulator/beam/dist.c16
-rw-r--r--erts/emulator/beam/erl_afit_alloc.c6
-rw-r--r--erts/emulator/beam/erl_afit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_alloc.c94
-rw-r--r--erts/emulator/beam/erl_alloc.h20
-rw-r--r--erts/emulator/beam/erl_alloc.types1
-rw-r--r--erts/emulator/beam/erl_alloc_util.c151
-rw-r--r--erts/emulator/beam/erl_alloc_util.h2
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.c22
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.c24
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.h2
-rwxr-xr-xerts/emulator/beam/erl_bif_info.c68
-rw-r--r--erts/emulator/beam/erl_bif_port.c173
-rw-r--r--erts/emulator/beam/erl_bif_trace.c4
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.c14
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_instrument.c97
-rw-r--r--erts/emulator/beam/erl_lock_check.c4
-rw-r--r--erts/emulator/beam/erl_monitors.c20
-rw-r--r--erts/emulator/beam/erl_monitors.h2
-rw-r--r--erts/emulator/beam/erl_mtrace.c44
-rw-r--r--erts/emulator/beam/erl_node_tables.c6
-rw-r--r--erts/emulator/beam/erl_port.h22
-rw-r--r--erts/emulator/beam/erl_port_task.c28
-rw-r--r--erts/emulator/beam/erl_port_task.h2
-rw-r--r--erts/emulator/beam/erl_process.c12
-rw-r--r--erts/emulator/beam/erl_process.h3
-rw-r--r--erts/emulator/beam/erl_process_dump.c37
-rw-r--r--erts/emulator/beam/external.c15
-rw-r--r--erts/emulator/beam/io.c323
-rw-r--r--erts/emulator/drivers/common/inet_drv.c131
-rw-r--r--erts/emulator/drivers/unix/ttsl_drv.c47
-rw-r--r--erts/emulator/drivers/win32/ttsl_drv.c4
-rw-r--r--erts/emulator/hipe/hipe_x86_signal.c1
-rw-r--r--erts/emulator/internal_doc/dec.erl5
-rw-r--r--erts/emulator/sys/common/erl_mseg.c27
-rw-r--r--erts/emulator/sys/common/erl_mseg.h5
-rw-r--r--erts/emulator/sys/unix/sys_float.c4
-rwxr-xr-xerts/emulator/sys/win32/sys.c26
-rw-r--r--erts/emulator/sys/win32/sys_float.c8
-rw-r--r--erts/emulator/test/busy_port_SUITE.erl2
-rw-r--r--erts/emulator/test/code_parallel_load_SUITE.erl1
-rw-r--r--erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c4
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c75
-rw-r--r--erts/etc/unix/cerl.src5
-rw-r--r--erts/lib_src/Makefile.in8
-rw-r--r--erts/preloaded/ebin/erlang.beambin93388 -> 92912 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin3644 -> 3276 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin70084 -> 70216 bytes
-rw-r--r--erts/preloaded/src/erlang.erl22
-rw-r--r--erts/preloaded/src/erts_internal.erl16
-rw-r--r--erts/preloaded/src/prim_inet.erl31
-rw-r--r--lib/asn1/doc/src/notes.xml17
-rw-r--r--lib/asn1/src/Makefile10
-rw-r--r--lib/asn1/src/asn1ct_check.erl8
-rw-r--r--lib/asn1/test/asn1_SUITE.erl5
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Param2.asn148
-rw-r--r--lib/asn1/test/testParameterizedInfObj.erl57
-rw-r--r--lib/asn1/vsn.mk2
-rw-r--r--lib/common_test/priv/ct_default.css8
-rw-r--r--lib/common_test/src/ct_config.erl10
-rw-r--r--lib/common_test/src/ct_framework.erl11
-rw-r--r--lib/common_test/src/ct_logs.erl1095
-rw-r--r--lib/common_test/src/ct_run.erl14
-rw-r--r--lib/common_test/src/ct_telnet.erl73
-rw-r--r--lib/common_test/src/ct_telnet_client.erl8
-rw-r--r--lib/common_test/src/ct_util.erl4
-rw-r--r--lib/common_test/src/cth_log_redirect.erl8
-rw-r--r--lib/common_test/src/unix_telnet.erl36
-rw-r--r--lib/common_test/test/Makefile1
-rw-r--r--lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl50
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl70
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_telnet_SUITE.erl80
-rw-r--r--lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl184
-rw-r--r--lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_timetrap_SUITE.erl76
-rw-r--r--lib/common_test/test/ct_test_support.erl39
-rw-r--r--lib/common_test/test/telnet_server.erl228
-rw-r--r--lib/compiler/src/beam_receive.erl92
-rw-r--r--lib/compiler/src/compile.erl20
-rw-r--r--lib/compiler/test/compile_SUITE.erl10
-rw-r--r--lib/compiler/test/compile_SUITE_data/key_compatibility.beambin0 -> 844 bytes
-rw-r--r--lib/compiler/test/compile_SUITE_data/key_compatibility.erl8
-rw-r--r--lib/compiler/test/receive_SUITE.erl13
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S71
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl6
-rw-r--r--lib/crypto/c_src/crypto.c863
-rw-r--r--[-rwxr-xr-x]lib/crypto/doc/src/crypto.xml1588
-rw-r--r--lib/crypto/doc/src/crypto_app.xml79
-rw-r--r--lib/crypto/src/crypto.erl712
-rw-r--r--lib/crypto/test/Makefile3
-rw-r--r--lib/crypto/test/crypto_SUITE.erl3267
-rw-r--r--lib/crypto/test/old_crypto_SUITE.erl2342
-rw-r--r--lib/debugger/src/dbg_debugged.erl14
-rw-r--r--lib/debugger/src/dbg_istk.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_gui.erl5
-rw-r--r--lib/dialyzer/src/dialyzer_gui_wx.erl5
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl8
-rw-r--r--lib/diameter/src/Makefile2
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c3
-rw-r--r--lib/et/doc/src/et_desc.xmlsrc2
-rw-r--r--lib/et/src/et_collector.erl9
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Environment.java4
-rw-r--r--lib/ic/src/icparse.yrl3
-rw-r--r--lib/inets/src/http_server/httpd_manager.erl4
-rw-r--r--lib/inets/test/erl_make_certs.erl107
-rw-r--r--lib/jinterface/test/jinterface_SUITE.erl3
-rw-r--r--lib/jinterface/test/jitu.erl38
-rw-r--r--lib/jinterface/test/nc_SUITE.erl12
-rw-r--r--lib/kernel/doc/src/inet.xml4
-rw-r--r--lib/kernel/src/application_master.erl9
-rw-r--r--lib/kernel/src/disk_log.erl18
-rw-r--r--lib/kernel/src/file.erl43
-rw-r--r--lib/kernel/src/file_io_server.erl3
-rw-r--r--lib/kernel/src/file_server.erl3
-rw-r--r--lib/kernel/src/gen_sctp.erl4
-rw-r--r--lib/kernel/src/gen_udp.erl4
-rw-r--r--lib/kernel/src/inet.erl5
-rw-r--r--lib/kernel/src/inet_gethost_native.erl3
-rw-r--r--lib/kernel/src/inet_int.hrl4
-rw-r--r--lib/kernel/src/os.erl23
-rw-r--r--lib/kernel/src/rpc.erl24
-rw-r--r--lib/kernel/test/file_SUITE.erl29
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl3
-rw-r--r--lib/kernel/test/global_SUITE_data/global_trace.erl9
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE.erl8
-rw-r--r--lib/kernel/test/os_SUITE.erl45
-rw-r--r--lib/megaco/.gitignore35
-rw-r--r--lib/megaco/doc/src/Makefile5
-rw-r--r--lib/megaco/doc/src/notes.xml781
-rw-r--r--lib/megaco/src/app/megaco.appup.src326
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src31
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_handler.erl6
-rw-r--r--lib/megaco/test/megaco_appup_test.erl31
-rw-r--r--lib/megaco/test/megaco_codec_flex_lib.erl8
-rw-r--r--lib/megaco/test/megaco_codec_prev3a_test.erl140
-rw-r--r--lib/megaco/test/megaco_codec_prev3b_test.erl147
-rw-r--r--lib/megaco/test/megaco_codec_prev3c_test.erl150
-rw-r--r--lib/megaco/test/megaco_codec_v1_test.erl110
-rw-r--r--lib/megaco/test/megaco_codec_v2_test.erl1103
-rw-r--r--lib/megaco/test/megaco_codec_v3_test.erl147
-rw-r--r--lib/megaco/test/megaco_test_lib.erl167
-rw-r--r--lib/megaco/vsn.mk2
-rw-r--r--lib/mnesia/src/mnesia_index.erl10
-rw-r--r--lib/mnesia/src/mnesia_loader.erl14
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl51
-rw-r--r--lib/orber/src/orber_iiop_outproxy.erl35
-rw-r--r--lib/public_key/asn1/ECPrivateKey.asn124
-rw-r--r--lib/public_key/asn1/OTP-PKIX.asn130
-rw-r--r--lib/public_key/asn1/OTP-PUB-KEY.set.asn1
-rw-r--r--lib/public_key/asn1/PKCS-1.asn132
-rw-r--r--lib/public_key/asn1/PKIX1Algorithms88.asn1118
-rw-r--r--lib/public_key/doc/src/public_key.xml47
-rw-r--r--lib/public_key/include/public_key.hrl8
-rw-r--r--lib/public_key/src/pubkey_cert_records.erl88
-rw-r--r--lib/public_key/src/pubkey_pbe.erl64
-rw-r--r--lib/public_key/src/pubkey_pem.erl16
-rw-r--r--lib/public_key/src/pubkey_ssh.erl41
-rw-r--r--lib/public_key/src/public_key.erl177
-rw-r--r--lib/public_key/test/erl_make_certs.erl117
-rw-r--r--lib/public_key/test/pbe_SUITE.erl14
-rw-r--r--lib/public_key/test/pkits_SUITE.erl13
-rw-r--r--lib/public_key/test/public_key_SUITE.erl2
-rw-r--r--lib/reltool/src/reltool_utils.erl2
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl6
-rw-r--r--lib/runtime_tools/src/dbg.erl6
-rw-r--r--lib/runtime_tools/src/ttb_autostart.erl1
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl8
-rw-r--r--lib/snmp/src/agent/snmp_user_based_sm_mib.erl33
-rw-r--r--lib/snmp/src/agent/snmpa_target_cache.erl37
-rw-r--r--lib/snmp/src/misc/snmp_usm.erl48
-rw-r--r--lib/ssh/src/ssh_bits.erl27
-rw-r--r--lib/ssh/src/ssh_cli.erl4
-rw-r--r--lib/ssh/src/ssh_math.erl96
-rw-r--r--lib/ssh/src/ssh_transport.erl41
-rw-r--r--lib/ssh/src/ssh_xfer.erl26
-rw-r--r--lib/ssl/doc/src/ssl.xml15
-rw-r--r--lib/ssl/src/Makefile2
-rw-r--r--lib/ssl/src/ssl.erl19
-rw-r--r--lib/ssl/src/ssl_certificate.erl15
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl452
-rw-r--r--lib/ssl/src/ssl_cipher.hrl120
-rw-r--r--lib/ssl/src/ssl_connection.erl210
-rw-r--r--lib/ssl/src/ssl_handshake.erl351
-rw-r--r--lib/ssl/src/ssl_handshake.hrl52
-rw-r--r--lib/ssl/src/ssl_internal.hrl6
-rw-r--r--lib/ssl/src/ssl_manager.erl4
-rw-r--r--lib/ssl/src/ssl_record.erl11
-rw-r--r--lib/ssl/src/ssl_srp_primes.hrl1
-rw-r--r--lib/ssl/src/ssl_ssl3.erl10
-rw-r--r--lib/ssl/src/ssl_tls1.erl171
-rw-r--r--lib/ssl/test/erl_make_certs.erl107
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl206
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl18
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl16
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_test_lib.erl314
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl131
-rw-r--r--lib/stdlib/doc/src/lists.xml25
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml1
-rw-r--r--lib/stdlib/src/beam_lib.erl16
-rw-r--r--lib/stdlib/src/dets.erl9
-rw-r--r--lib/stdlib/src/epp.erl5
-rw-r--r--lib/stdlib/src/erl_pp.erl33
-rw-r--r--lib/stdlib/src/gen_server.erl18
-rw-r--r--lib/stdlib/src/io.erl6
-rw-r--r--lib/stdlib/src/lists.erl24
-rw-r--r--lib/stdlib/src/otp_internal.erl177
-rw-r--r--lib/stdlib/src/supervisor.erl27
-rw-r--r--lib/stdlib/src/timer.erl4
-rw-r--r--lib/stdlib/test/Makefile1
-rw-r--r--lib/stdlib/test/epp_SUITE.erl4
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl3
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl43
-rw-r--r--lib/stdlib/test/ets_SUITE.erl68
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl16
-rw-r--r--lib/stdlib/test/lists_SUITE.erl4
-rw-r--r--lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl215
-rw-r--r--lib/stdlib/test/shell_SUITE.erl3
-rw-r--r--lib/stdlib/test/supervisor_3.erl45
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl106
-rw-r--r--lib/stdlib/test/zip_SUITE.erl25
-rw-r--r--lib/test_server/src/erl2html2.erl3
-rw-r--r--lib/test_server/src/test_server_ctrl.erl4
-rw-r--r--lib/test_server/src/test_server_io.erl17
-rw-r--r--lib/test_server/test/test_server_SUITE.erl13
-rw-r--r--lib/tools/src/fprof.erl8
-rw-r--r--make/run_make.mk2
267 files changed, 13476 insertions, 7607 deletions
diff --git a/.gitignore b/.gitignore
index a3e03dc46f..7ccedd3ff3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -287,13 +287,13 @@ JAVADOC-GENERATED
# otp_mibs
-/lib/otp_mibs/include/[A-Z]*.hrl
+/lib/otp_mibs/include/OTP*.hrl
/lib/otp_mibs/mibs/v1/OTP*.mib.v1
/lib/otp_mibs/priv/mibs/OTP*.bin
# os_mon
-/lib/os_mon/include/[A-Z]*.hrl
+/lib/os_mon/include/OTP*.hrl
/lib/os_mon/mibs/v1/OTP*.mib.v1
/lib/os_mon/priv/mibs/OTP*.bin
diff --git a/bootstrap/lib/compiler/ebin/beam_receive.beam b/bootstrap/lib/compiler/ebin/beam_receive.beam
index afc5eaa333..2f1fcc9fe1 100644
--- a/bootstrap/lib/compiler/ebin/beam_receive.beam
+++ b/bootstrap/lib/compiler/ebin/beam_receive.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index e87e6a8555..ba17952caf 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_master.beam b/bootstrap/lib/kernel/ebin/application_master.beam
index e73de8b687..0af5dc0e00 100644
--- a/bootstrap/lib/kernel/ebin/application_master.beam
+++ b/bootstrap/lib/kernel/ebin/application_master.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log.beam b/bootstrap/lib/kernel/ebin/disk_log.beam
index 96f63b364c..5ec7cfe5eb 100644
--- a/bootstrap/lib/kernel/ebin/disk_log.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file.beam b/bootstrap/lib/kernel/ebin/file.beam
index d74d356bfb..9906ddd1fe 100644
--- a/bootstrap/lib/kernel/ebin/file.beam
+++ b/bootstrap/lib/kernel/ebin/file.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam
index 2c617ae7e4..6916cdcc58 100644
--- a/bootstrap/lib/kernel/ebin/file_io_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_io_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_server.beam b/bootstrap/lib/kernel/ebin/file_server.beam
index 211b2df642..2ebded8ba5 100644
--- a/bootstrap/lib/kernel/ebin/file_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
index f1f3bdcd8d..03cb896d1c 100644
--- a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
+++ b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/os.beam b/bootstrap/lib/kernel/ebin/os.beam
index 3972fe7b91..bb981bbf89 100644
--- a/bootstrap/lib/kernel/ebin/os.beam
+++ b/bootstrap/lib/kernel/ebin/os.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/rpc.beam b/bootstrap/lib/kernel/ebin/rpc.beam
index 305779539a..4782908361 100644
--- a/bootstrap/lib/kernel/ebin/rpc.beam
+++ b/bootstrap/lib/kernel/ebin/rpc.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam
index 37ed5b2bf8..611f271cb9 100644
--- a/bootstrap/lib/stdlib/ebin/beam_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam
index b9a5866d30..979a471a98 100644
--- a/bootstrap/lib/stdlib/ebin/dets.beam
+++ b/bootstrap/lib/stdlib/ebin/dets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam
index 59e07c65c2..879370ef87 100644
--- a/bootstrap/lib/stdlib/ebin/epp.beam
+++ b/bootstrap/lib/stdlib/ebin/epp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen.beam b/bootstrap/lib/stdlib/ebin/gen.beam
index 77d0bf806a..277a881630 100644
--- a/bootstrap/lib/stdlib/ebin/gen.beam
+++ b/bootstrap/lib/stdlib/ebin/gen.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam
index cee9abfd5d..313bd2dcce 100644
--- a/bootstrap/lib/stdlib/ebin/gen_event.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_event.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
index 1fcabac0d7..561b562115 100644
--- a/bootstrap/lib/stdlib/ebin/gen_fsm.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam
index f0fa4f03a9..ac948974cc 100644
--- a/bootstrap/lib/stdlib/ebin/gen_server.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io.beam b/bootstrap/lib/stdlib/ebin/io.beam
index 73cf837dfb..19ae65b3bf 100644
--- a/bootstrap/lib/stdlib/ebin/io.beam
+++ b/bootstrap/lib/stdlib/ebin/io.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/lists.beam b/bootstrap/lib/stdlib/ebin/lists.beam
index cf189f2ae5..332a2088d0 100644
--- a/bootstrap/lib/stdlib/ebin/lists.beam
+++ b/bootstrap/lib/stdlib/ebin/lists.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam
index c853cf37bd..c19ca1763a 100644
--- a/bootstrap/lib/stdlib/ebin/otp_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam
index 9bf3439674..e68e59dacd 100644
--- a/bootstrap/lib/stdlib/ebin/supervisor.beam
+++ b/bootstrap/lib/stdlib/ebin/supervisor.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sys.beam b/bootstrap/lib/stdlib/ebin/sys.beam
index 841874f1f5..7e2ba3c19b 100644
--- a/bootstrap/lib/stdlib/ebin/sys.beam
+++ b/bootstrap/lib/stdlib/ebin/sys.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/timer.beam b/bootstrap/lib/stdlib/ebin/timer.beam
index 5f8f714a78..4269f1ebec 100644
--- a/bootstrap/lib/stdlib/ebin/timer.beam
+++ b/bootstrap/lib/stdlib/ebin/timer.beam
Binary files differ
diff --git a/erts/configure.in b/erts/configure.in
index 2ee907b6e4..b9c9a76ef6 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -1342,6 +1342,17 @@ if test "x$TERMCAP_LIB" != "x"; then
AC_DEFINE(HAVE_TERMCAP, 1, [Define if termcap functions exists])
fi
+if test "X$host" != "Xwin32"; then
+ AC_MSG_CHECKING(for wcwidth)
+ AC_TRY_LINK([#include <wchar.h>], [wcwidth(0);],
+ have_wcwidth=yes, have_wcwidth=no)
+ if test $have_wcwidth = yes; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_WCWIDTH, [1],
+ [Define to 1 if you have a `wcwidth' function.])
+ fi
+fi
+
dnl -------------
dnl zlib
dnl -------------
@@ -3576,10 +3587,7 @@ DED_EXT=so
case $host_os in
win32) DED_EXT=dll;;
darwin*)
- DED_CFLAGS="$DED_CFLAGS -fno-common"
- if test "X$STATIC_CFLAGS" = "X"; then
- STATIC_CFLAGS="-mdynamic-no-pic"
- fi;;
+ DED_CFLAGS="$DED_CFLAGS -fno-common";;
*)
;;
esac
diff --git a/erts/doc/src/crash_dump.xml b/erts/doc/src/crash_dump.xml
index b3c4671c3d..73212e6143 100644
--- a/erts/doc/src/crash_dump.xml
+++ b/erts/doc/src/crash_dump.xml
@@ -290,6 +290,10 @@
<em>Stack+heap</em>, <em>OldHeap</em>, <em>Heap unused</em>
and <em>OldHeap unused</em> do not exist. Instead this field
presents the size of the process' stack.</item>
+ <tag><em>Memory</em></tag>
+ <item>The total memory used by this process. This includes call stack,
+ heap and internal structures. Same as <seealso marker="erlang#process_info-2">erlang:process_info(Pid,memory)</seealso>.
+ </item>
<tag><em>Program counter</em></tag>
<item>The current instruction pointer. This is only interesting for
runtime system developers. The function into which the program
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index 1f7c5b5a7f..a68e62d051 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -536,15 +536,35 @@
<tag><marker id="file_name_encoding"></marker><c><![CDATA[+fnl]]></c></tag>
<item>
<p>The VM works with file names as if they are encoded using the ISO-latin-1 encoding, disallowing Unicode characters with codepoints beyond 255. This is default on operating systems that have transparent file naming, i.e. all Unixes except MacOSX.</p>
+ <p>See <seealso marker="stdlib:unicode_usage#unicode_file_names">STDLIB User's Guide</seealso> for more infomation about unicode file names.</p>
</item>
- <tag><c><![CDATA[+fnu]]></c></tag>
+ <tag><c><![CDATA[+fnu[{w|i|e}]]]></c></tag>
<item>
<p>The VM works with file names as if they are encoded using UTF-8 (or some other system specific Unicode encoding). This is the default on operating systems that enforce Unicode encoding, i.e. Windows and MacOSX.</p>
- <p>By enabling Unicode file name translation on systems where this is not default, you open up to the possibility that some file names can not be interpreted by the VM and therefore will be returned to the program as raw binaries. The option is therefore considered experimental.</p>
- </item>
- <tag><c><![CDATA[+fna]]></c></tag>
- <item>
- <p>Selection between <c>+fnl</c> and <c>+fnu</c> is done based on the current locale settings in the OS, meaning that if you have set your terminal for UTF-8 encoding, the filesystem is expected to use the same encoding for filenames (use with care).</p>
+ <p>The <c>+fnu</c> switch can be followed by <c>w</c>,
+ <c>i</c>, or <c>e</c> to control the way wrongly encoded file
+ names are to be reported. <c>w</c> means that a warning is
+ sent to the <c>error_logger</c> whenever a wrongly encoded
+ file name is "skipped" in directory listings, <c>i</c> means
+ that those wrongly encoded file names are silently ignored and
+ <c>e</c> means that the API function will return an error
+ whenever a wrongly encoded file (or directory) name is
+ encountered. <c>w</c> is the default. Note that
+ <c>file:read_link/1</c> will always return an error if the
+ link points to an invalid file name.</p>
+ <p>See <seealso marker="stdlib:unicode_usage#unicode_file_names">STDLIB User's Guide</seealso> for more infomation about unicode file names.</p>
+ </item>
+ <tag><c><![CDATA[+fna[{w|i|e}]]]></c></tag>
+ <item>
+ <p>Selection between <c>+fnl</c> and <c>+fnu</c> is done based on the current locale settings in the OS, meaning that if you have set your terminal for UTF-8 encoding, the filesystem is expected to use the same encoding for file names (use with care).</p>
+ <p>The <c>+fna</c> switch can be followed by <c>w</c>,
+ <c>i</c>, or <c>e</c>. This will have effect if the locale
+ settings cause the behavior of <c>+fnu</c> to be selected.
+ See the description of <c>+fnu</c> above. If the locale
+ settings cause the behavior of <c>+fnl</c> to be selected,
+ then <c>w</c>, <c>i</c>, or <c>e</c> will not have any
+ effect.</p>
+ <p>See <seealso marker="stdlib:unicode_usage#unicode_file_names">STDLIB User's Guide</seealso> for more infomation about unicode file names.</p>
</item>
<tag><c><![CDATA[+hms Size]]></c></tag>
<item>
@@ -571,9 +591,9 @@
</item>
<tag><c><![CDATA[+L]]></c></tag>
<item>
- <p>Don't load information about source filenames and line numbers.
+ <p>Don't load information about source file names and line numbers.
This will save some memory, but exceptions will not contain
- information about the filenames and line numbers.
+ information about the file names and line numbers.
</p>
</item>
<tag><marker id="erts_alloc"><c><![CDATA[+MFlag Value]]></c></marker></tag>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index c9c46afa4b..3a2c644ff7 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -30,6 +30,29 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 5.10.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A bug in the implementation of offline schedulers has
+ been fixed. The bug was introduced in OTP-R16A/ERTS-5.10,
+ and caused work-stealing between schedulers to fail. This
+ in turn, caused work to accumulate in some run-queues.
+ The bug was only triggered when there were offline
+ schedulers in the system, i.e., when the amount of online
+ schedulers was less than the total amount of schedulers.
+ The effect of the bug got more severe the larger amount
+ of offline schedulers the system had.</p>
+ <p>
+ Own Id: OTP-11022 Aux Id: OTP-9892 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 5.10.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 4f2f647742..fb4cde0e76 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -48,6 +48,7 @@ CREATE_DIRS=
LDFLAGS=@LDFLAGS@
ARFLAGS=rc
+OMIT_OMIT_FP=no
ifeq ($(TYPE),debug)
PURIFY =
@@ -113,6 +114,13 @@ TYPEMARKER = .lcnt
TYPE_FLAGS = @CFLAGS@ -DERTS_ENABLE_LOCK_COUNT
else
+ifeq ($(TYPE),frmptr)
+PURIFY =
+OMIT_OMIT_FP=yes
+TYPEMARKER = .frmptr
+TYPE_FLAGS = @CFLAGS@ -DERTS_FRMPTR
+else
+
# If type isn't one of the above, it *is* opt type...
override TYPE=opt
PURIFY =
@@ -126,6 +134,7 @@ endif
endif
endif
endif
+endif
#
# NOTE: When adding a new type update ERL_BUILD_TYPE_MARKER in sys/unix/sys.c
@@ -219,8 +228,6 @@ LIB_PREFIX=lib
LIB_SUFFIX=.a
endif
-OMIT_OMIT_FP=no
-
ifeq (@EMU_LOCK_CHECKING@,yes)
NO_INLINE_FUNCTIONS=true
endif
@@ -238,7 +245,7 @@ ifeq ($(NO_INLINE_FUNCTIONS),true)
GEN_OPT_FLGS = $(OPT_LEVEL) -fno-inline-functions
else
ifeq ($(OMIT_OMIT_FP),yes)
-GEN_OPT_FLGS = $(OPT_LEVEL)
+GEN_OPT_FLGS = $(OPT_LEVEL) -fno-omit-frame-pointer
else
GEN_OPT_FLGS = $(OPT_LEVEL) -fomit-frame-pointer
endif
@@ -1014,7 +1021,8 @@ endif
$(TARGET)/gen_git_version.mk:
# We touch beam/erl_bif.info.c if we regenerated the git version to force a
# rebuild.
- if $(gen_verbose)utils/gen_git_version $@; then touch beam/erl_bif_info.c; fi
+ $(gen_verbose)
+ $(V_at)if utils/gen_git_version $@; then touch beam/erl_bif_info.c; fi
.PHONY: depend
ifdef VOID_EMULATOR
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index bd4e5a52d0..4193eb4f3f 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -2964,19 +2964,19 @@ gen_put_integer(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
NEW_GENOP(stp, op);
NATIVE_ENDIAN(Flags);
- if (Size.type == TAG_i && Size.val < 0) {
- error:
/* Negative size must fail */
- op->op = genop_badarg_1;
- op->arity = 1;
- op->a[0] = Fail;
- } else if (Size.type == TAG_i) {
+ if (Size.type == TAG_i) {
op->op = genop_i_new_bs_put_integer_imm_4;
op->arity = 4;
op->a[0] = Fail;
op->a[1].type = TAG_u;
if (!safe_mul(Size.val, Unit.val, &op->a[1].val)) {
- goto error;
+ error:
+ op->op = genop_badarg_1;
+ op->arity = 1;
+ op->a[0] = Fail;
+ op->next = NULL;
+ return op;
}
op->a[1].val = Size.val * Unit.val;
op->a[2].type = Flags.type;
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 8bc994c8c3..dc8e9101de 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -154,8 +154,10 @@ bif erts_internal:port_command/3
bif erts_internal:port_control/3
bif erts_internal:port_close/1
bif erts_internal:port_connect/2
-bif erts_internal:port_set_data/2
-bif erts_internal:port_get_data/1
+
+# inet_db support
+bif erlang:port_set_data/2
+bif erlang:port_get_data/1
# Tracing & debugging.
bif erlang:trace_pattern/2
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index 9260c0c4b8..6f9b171224 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -2528,17 +2528,18 @@ const byte d_base_exp_lookup[] = { 31, 19, 15, 13, 11, 11, 10, 9, 9, 8, 8, 8, 8,
* end
* How much can the characters which fit in 31 bit represent
*/
-const Uint d_base_base_lookup[] = { 2147483648, 1162261467, 1073741824,
- 1220703125, 362797056, 1977326743, 1073741824, 387420489, 1000000000,
- 214358881, 429981696, 815730721, 1475789056, 170859375, 268435456,
- 410338673, 612220032, 893871739, 1280000000, 1801088541, 113379904,
- 148035889, 191102976, 244140625, 308915776, 387420489, 481890304,
- 594823321, 729000000, 887503681, 1073741824, 1291467969, 1544804416,
- 1838265625, 60466176, 69343957, 79235168, 90224199, 102400000,
- 115856201, 130691232, 147008443, 164916224, 184528125, 205962976,
- 229345007, 254803968, 282475249, 312500000, 345025251, 380204032,
- 418195493, 459165024, 503284375, 550731776, 601692057, 656356768,
- 714924299, 777600000, 844596301, 916132832, 992436543, 1073741824 };
+const Uint d_base_base_lookup[] = { 2147483648u, 1162261467u, 1073741824u,
+ 1220703125u, 362797056u, 1977326743u, 1073741824u, 387420489u,
+ 1000000000u, 214358881u, 429981696u, 815730721u, 1475789056u,
+ 170859375u, 268435456u, 410338673u, 612220032u, 893871739u, 1280000000u,
+ 1801088541u, 113379904u, 148035889u, 191102976u, 244140625u, 308915776u,
+ 387420489u, 481890304u, 594823321u, 729000000u, 887503681u, 1073741824u,
+ 1291467969u, 1544804416u, 1838265625u, 60466176u, 69343957u, 79235168u,
+ 90224199u, 102400000u, 115856201u, 130691232u, 147008443u, 164916224u,
+ 184528125u, 205962976u, 229345007u, 254803968u, 282475249u, 312500000u,
+ 345025251u, 380204032u, 418195493u, 459165024u, 503284375u, 550731776u,
+ 601692057u, 656356768u, 714924299u, 777600000u, 844596301u, 916132832u,
+ 992436543u, 1073741824u };
Eterm erts_chars_to_integer(Process *BIF_P, char *bytes,
Uint size, const int base) {
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 9aa1e5f30d..f8cfd60a6f 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -331,6 +331,7 @@ print_process_info(int to, void *to_arg, Process *p)
erts_print(to, to_arg, "Heap unused: %bpu\n", (p->hend - p->htop));
erts_print(to, to_arg, "OldHeap unused: %bpu\n",
(OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HTOP(p)) );
+ erts_print(to, to_arg, "Memory: %beu\n", erts_process_memory(p));
if (garbing) {
print_garb_info(to, to_arg, p);
@@ -753,7 +754,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
return; /* Can't create the crash dump, skip it */
time(&now);
- erts_fdprintf(fd, "=erl_crash_dump:0.1\n%s", ctime(&now));
+ erts_fdprintf(fd, "=erl_crash_dump:0.2\n%s", ctime(&now));
if (file != NULL)
erts_fdprintf(fd, "The error occurred in file %s, line %d\n", file, line);
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 0781665f05..44f4eb9d43 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -455,7 +455,7 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
Eterm nd_reason = (reason == am_no_network
? am_no_network
: am_net_kernel_terminated);
- erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_rlock(&erts_dist_table_rwmtx);
for (tdep = erts_hidden_dist_entries; tdep; tdep = tdep->next)
no_dist_port++;
@@ -464,7 +464,7 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
/* KILL all port controllers */
if (no_dist_port == 0)
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
else {
Eterm def_buf[128];
int i = 0;
@@ -483,7 +483,7 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
ASSERT(is_internal_port(tdep->cid));
dist_port[i++] = tdep->cid;
}
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
for (i = 0; i < no_dist_port; i++) {
Port *prt = erts_port_lookup(dist_port[i],
@@ -2560,9 +2560,9 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2)
erts_smp_proc_unlock(net_kernel, ERTS_PROC_LOCK_MAIN);
#ifdef DEBUG
- erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_rlock(&erts_dist_table_rwmtx);
ASSERT(!erts_visible_dist_entries && !erts_hidden_dist_entries);
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
#endif
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
@@ -2912,7 +2912,7 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1)
length = 0;
- erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_rlock(&erts_dist_table_rwmtx);
ASSERT(erts_no_of_not_connected_dist_entries >= 0);
ASSERT(erts_no_of_hidden_dist_entries >= 0);
@@ -2929,7 +2929,7 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1)
result = NIL;
if (length == 0) {
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
goto done;
}
@@ -2958,7 +2958,7 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1)
hp += 2;
}
ASSERT(endp == hp);
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
done:
UnUseTmpHeap(2,BIF_P);
diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c
index 5850f80843..b45201af42 100644
--- a/erts/emulator/beam/erl_afit_alloc.c
+++ b/erts/emulator/beam/erl_afit_alloc.c
@@ -259,10 +259,10 @@ info_options(Allctr_t *allctr,
* to erts_afalc_test() *
\* */
-unsigned long
-erts_afalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_afalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- default: ASSERT(0); return ~((unsigned long) 0);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_afit_alloc.h b/erts/emulator/beam/erl_afit_alloc.h
index cf7b99c463..b90ac8f7c5 100644
--- a/erts/emulator/beam/erl_afit_alloc.h
+++ b/erts/emulator/beam/erl_afit_alloc.h
@@ -56,7 +56,7 @@ struct AFAllctr_t_ {
AFFreeBlock_t * free_list;
};
-unsigned long erts_afalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_afalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_AF_ALLOC_IMPL)
&& !defined(ERL_AF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index d748f86d75..9de4ef1ff9 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -495,6 +495,38 @@ refuse_af_strategy(struct au_init *init)
static void hdbg_init(void);
#endif
+static void adjust_fix_alloc_sizes(UWord extra_block_size)
+{
+
+ if (extra_block_size && erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].enabled) {
+ int j;
+
+#ifdef ERTS_SMP
+ if (erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].thr_spec) {
+ int i;
+ ErtsAllocatorThrSpec_t* tspec;
+
+ tspec = &erts_allctr_thr_spec[ERTS_ALC_A_FIXED_SIZE];
+ ASSERT(tspec->enabled);
+
+ for (i=0; i < tspec->size; i++) {
+ Allctr_t* allctr = tspec->allctr[i];
+ for (j=0; j < ERTS_ALC_NO_FIXED_SIZES; ++j) {
+ allctr->fix[j].type_size += extra_block_size;
+ }
+ }
+ }
+ else
+#endif
+ {
+ Allctr_t* allctr = erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].extra;
+ for (j=0; j < ERTS_ALC_NO_FIXED_SIZES; ++j) {
+ allctr->fix[j].type_size += extra_block_size;
+ }
+ }
+ }
+}
+
void
erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
{
@@ -515,9 +547,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
= sizeof(Process);
#if !HALFWORD_HEAP
fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_MONITOR_SH)]
- = ERTS_MONITOR_SH_SIZE;
+ = ERTS_MONITOR_SH_SIZE * sizeof(Uint);
fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_NLINK_SH)]
- = ERTS_LINK_SH_SIZE;
+ = ERTS_LINK_SH_SIZE * sizeof(Uint);
#endif
fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_DRV_EV_D_STATE)]
= sizeof(ErtsDrvEventDataState);
@@ -538,6 +570,8 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
if (ncpu < 1)
ncpu = 1;
+ erts_tsd_key_create(&erts_allctr_prelock_tsd_key);
+
erts_sys_alloc_init();
erts_init_utils_mem();
@@ -768,7 +802,7 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
#ifdef DEBUG
extra_block_size += install_debug_functions();
#endif
-
+ adjust_fix_alloc_sizes(extra_block_size);
}
void
@@ -3107,6 +3141,55 @@ erts_request_alloc_info(struct process *c_p,
return 1;
}
+/*
+ * The allocator wrapper prelocking stuff below is about the locking order.
+ * It only affects wrappers (erl_mtrace.c and erl_instrument.c) that keep locks
+ * during alloc/realloc/free.
+ *
+ * Some query functions in erl_alloc_util.c lock the allocator mutex and then
+ * use erts_printf that in turn may call the sys allocator through the wrappers.
+ * To avoid breaking locking order these query functions first "pre-locks" all
+ * allocator wrappers.
+ */
+ErtsAllocatorWrapper_t *erts_allctr_wrappers;
+int erts_allctr_wrapper_prelocked = 0;
+erts_tsd_key_t erts_allctr_prelock_tsd_key;
+
+void erts_allctr_wrapper_prelock_init(ErtsAllocatorWrapper_t* wrapper)
+{
+ ASSERT(wrapper->lock && wrapper->unlock);
+ wrapper->next = erts_allctr_wrappers;
+ erts_allctr_wrappers = wrapper;
+}
+
+void erts_allctr_wrapper_pre_lock(void)
+{
+ if (erts_allctr_wrappers) {
+ ErtsAllocatorWrapper_t* wrapper = erts_allctr_wrappers;
+ for ( ; wrapper; wrapper = wrapper->next) {
+ wrapper->lock();
+ }
+ ASSERT(!erts_allctr_wrapper_prelocked);
+ erts_allctr_wrapper_prelocked = 1;
+ erts_tsd_set(erts_allctr_prelock_tsd_key, (void*)1);
+ }
+}
+
+void erts_allctr_wrapper_pre_unlock(void)
+{
+ if (erts_allctr_wrappers) {
+ ErtsAllocatorWrapper_t* wrapper = erts_allctr_wrappers;
+
+ erts_allctr_wrapper_prelocked = 0;
+ erts_tsd_set(erts_allctr_prelock_tsd_key, (void*)0);
+ for ( ; wrapper; wrapper = wrapper->next) {
+ wrapper->unlock();
+ }
+ }
+}
+
+
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Deprecated functions *
* *
@@ -3136,10 +3219,7 @@ void *safe_realloc(void *ptr, Uint sz)
\* */
#define ERTS_ALC_TEST_ABORT erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n")
-UWord erts_alc_test(UWord op,
- UWord a1,
- UWord a2,
- UWord a3)
+UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
{
switch (op >> 8) {
case 0x0: return erts_alcu_test(op, a1, a2);
diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h
index ba5ec9c367..9cafd8ddc8 100644
--- a/erts/emulator/beam/erl_alloc.h
+++ b/erts/emulator/beam/erl_alloc.h
@@ -135,6 +135,18 @@ typedef struct {
extern ErtsAllocatorThrSpec_t erts_allctr_thr_spec[ERTS_ALC_A_MAX+1];
+typedef struct ErtsAllocatorWrapper_t_ {
+ void (*lock)(void);
+ void (*unlock)(void);
+ struct ErtsAllocatorWrapper_t_* next;
+}ErtsAllocatorWrapper_t;
+ErtsAllocatorWrapper_t *erts_allctr_wrappers;
+extern int erts_allctr_wrapper_prelocked;
+extern erts_tsd_key_t erts_allctr_prelock_tsd_key;
+void erts_allctr_wrapper_prelock_init(ErtsAllocatorWrapper_t* wrapper);
+void erts_allctr_wrapper_pre_lock(void);
+void erts_allctr_wrapper_pre_unlock(void);
+
void erts_alloc_register_scheduler(void *vesdp);
#ifdef ERTS_SMP
void erts_alloc_scheduler_handle_delayed_dealloc(void *vesdp,
@@ -188,6 +200,7 @@ void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size);
void erts_free(ErtsAlcType_t type, void *ptr);
void *erts_alloc_fnf(ErtsAlcType_t type, Uint size);
void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size);
+int erts_is_allctr_wrapper_prelocked(void);
#endif /* #if !ERTS_ALC_DO_INLINE */
@@ -258,6 +271,13 @@ void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size)
size);
}
+ERTS_ALC_INLINE
+int erts_is_allctr_wrapper_prelocked(void)
+{
+ return erts_allctr_wrapper_prelocked /* locked */
+ && !!erts_tsd_get(erts_allctr_prelock_tsd_key); /* by me */
+}
+
#endif /* #if ERTS_ALC_DO_INLINE || defined(ERTS_ALC_INTERNAL__) */
#define ERTS_ALC_GET_THR_IX() ((int) erts_get_scheduler_id())
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 5e3615ccc2..5a92ab7f24 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -272,6 +272,7 @@ type CODE_IX_LOCK_Q SHORT_LIVED SYSTEM code_ix_lock_q
type PROC_INTERVAL LONG_LIVED SYSTEM process_interval
type BUSY_CALLER_TAB SHORT_LIVED SYSTEM busy_caller_table
type BUSY_CALLER SHORT_LIVED SYSTEM busy_caller
+type PORT_DATA_HEAP STANDARD SYSTEM port_data_heap
+if threads_no_smp
# Need thread safe allocs, but std_alloc and fix_alloc are not;
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index ac7f420708..53062979a6 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -588,17 +588,21 @@ do { \
#ifdef DEBUG
#ifdef USE_THREADS
+# ifdef ERTS_SMP
+# define IS_ACTUALLY_BLOCKING (erts_thr_progress_is_blocking())
+# else
+# define IS_ACTUALLY_BLOCKING 0
+# endif
#define ERTS_ALCU_DBG_CHK_THR_ACCESS(A) \
do { \
- if (!(A)->thread_safe) { \
- if (!(A)->debug.saved_tid) { \
+ if (!(A)->thread_safe && !IS_ACTUALLY_BLOCKING) { \
+ if (!(A)->debug.saved_tid) { \
(A)->debug.tid = erts_thr_self(); \
(A)->debug.saved_tid = 1; \
} \
else { \
ERTS_SMP_LC_ASSERT( \
- ethr_equal_tids((A)->debug.tid, erts_thr_self()) \
- || erts_thr_progress_is_blocking()); \
+ ethr_equal_tids((A)->debug.tid, erts_thr_self())); \
} \
} \
} while (0)
@@ -878,8 +882,10 @@ erts_alcu_fix_alloc_shrink(Allctr_t *allctr, erts_aint32_t flgs)
#ifdef ERTS_SMP
-#define ERTS_ALCU_DD_FIX_TYPE_OFFS \
- ((sizeof(ErtsAllctrDDBlock_t)-1)/sizeof(UWord) + 1)
+typedef struct {
+ ErtsAllctrDDBlock_t ddblock__; /* must be first */
+ ErtsAlcType_t fix_type;
+}ErtsAllctrFixDDBlock_t;
static ERTS_INLINE Allctr_t*
@@ -1180,7 +1186,7 @@ handle_delayed_dealloc(Allctr_t *allctr,
if (fix) {
ErtsAlcType_t type;
- type = (ErtsAlcType_t) ((UWord *) ptr)[ERTS_ALCU_DD_FIX_TYPE_OFFS];
+ type = ((ErtsAllctrFixDDBlock_t*) ptr)->fix_type;
ix = type - ERTS_ALC_N_MIN_A_FIXED_SIZE;
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 1);
fix[ix].used--;
@@ -1242,7 +1248,7 @@ enqueue_dealloc_other_instance(ErtsAlcType_t type,
int cinit)
{
if (allctr->fix)
- ((UWord *) ptr)[ERTS_ALCU_DD_FIX_TYPE_OFFS] = (UWord) type;
+ ((ErtsAllctrFixDDBlock_t*) ptr)->fix_type = type;
if (ddq_enqueue(type, &allctr->dd.q, ptr, cinit))
erts_alloc_notify_delayed_dealloc(allctr->ix);
@@ -2508,12 +2514,6 @@ static erts_mtx_t init_atoms_mtx;
static void
init_atoms(Allctr_t *allctr)
{
-
-#ifdef USE_THREADS
- if (allctr && allctr->thread_safe)
- erts_mtx_unlock(&allctr->mutex);
-#endif
-
erts_mtx_lock(&init_atoms_mtx);
if (!atoms_initialized) {
@@ -2604,18 +2604,13 @@ init_atoms(Allctr_t *allctr)
fix_type_atoms[ix] = am_atom_put(name, len);
}
}
-
- if (allctr) {
+ if (allctr && !allctr->atoms_initialized) {
make_name_atoms(allctr);
(*allctr->init_atoms)();
-#ifdef USE_THREADS
- if (allctr->thread_safe)
- erts_mtx_lock(&allctr->mutex);
-#endif
allctr->atoms_initialized = 1;
}
@@ -3243,17 +3238,21 @@ erts_alcu_info_options(Allctr_t *allctr,
{
Eterm res;
+ if (hpp || szp)
+ ensure_atoms_initialized(allctr);
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
+ erts_allctr_wrapper_pre_lock();
erts_mtx_lock(&allctr->mutex);
+ }
#endif
- if (hpp || szp)
- ensure_atoms_initialized(allctr);
res = info_options(allctr, print_to_p, print_to_arg, hpp, szp);
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
erts_mtx_unlock(&allctr->mutex);
+ erts_allctr_wrapper_pre_unlock();
+ }
#endif
return res;
}
@@ -3280,16 +3279,18 @@ erts_alcu_sz_info(Allctr_t *allctr,
return am_false;
}
+ if (hpp || szp)
+ ensure_atoms_initialized(allctr);
+
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
+ erts_allctr_wrapper_pre_lock();
erts_mtx_lock(&allctr->mutex);
+ }
#endif
ERTS_ALCU_DBG_CHK_THR_ACCESS(allctr);
- if (hpp || szp)
- ensure_atoms_initialized(allctr);
-
/* Update sbc values not continously updated */
allctr->sbcs.blocks.curr.no
= allctr->sbcs.curr.norm.mseg.no + allctr->sbcs.curr.norm.sys_alloc.no;
@@ -3325,13 +3326,16 @@ erts_alcu_sz_info(Allctr_t *allctr,
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
erts_mtx_unlock(&allctr->mutex);
+ erts_allctr_wrapper_pre_unlock();
+ }
#endif
return res;
}
+
Eterm
erts_alcu_info(Allctr_t *allctr,
int begin_max_period,
@@ -3352,16 +3356,18 @@ erts_alcu_info(Allctr_t *allctr,
return am_false;
}
+ if (hpp || szp)
+ ensure_atoms_initialized(allctr);
+
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
+ erts_allctr_wrapper_pre_lock();
erts_mtx_lock(&allctr->mutex);
+ }
#endif
ERTS_ALCU_DBG_CHK_THR_ACCESS(allctr);
- if (hpp || szp)
- ensure_atoms_initialized(allctr);
-
/* Update sbc values not continously updated */
allctr->sbcs.blocks.curr.no
= allctr->sbcs.curr.norm.mseg.no + allctr->sbcs.curr.norm.sys_alloc.no;
@@ -3414,8 +3420,10 @@ erts_alcu_info(Allctr_t *allctr,
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
erts_mtx_unlock(&allctr->mutex);
+ erts_allctr_wrapper_pre_unlock();
+ }
#endif
return res;
@@ -3487,7 +3495,9 @@ do_erts_alcu_alloc(ErtsAlcType_t type, void *extra, Uint size)
fix = allctr->fix;
if (fix) {
int ix = type - ERTS_ALC_N_MIN_A_FIXED_SIZE;
+ ASSERT((unsigned)ix < ERTS_ALC_NO_FIXED_SIZES);
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 1);
+ ASSERT(size <= fix[ix].type_size);
fix[ix].used++;
res = fix[ix].list;
if (res) {
@@ -3508,8 +3518,7 @@ do_erts_alcu_alloc(ErtsAlcType_t type, void *extra, Uint size)
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 0);
return res;
}
- if (size < 2*sizeof(UWord))
- size += sizeof(UWord);
+ size = fix[ix].type_size;
if (fix[ix].limit < fix[ix].used)
fix[ix].limit = fix[ix].used;
if (fix[ix].max_used < fix[ix].used)
@@ -4198,9 +4207,8 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
#if ERTS_SMP
if (init->tpref) {
Uint sz = ABLK_HDR_SZ;
- sz += ERTS_ALCU_DD_FIX_TYPE_OFFS*sizeof(UWord);
- if (init->fix)
- sz += sizeof(UWord);
+ sz += (init->fix ?
+ sizeof(ErtsAllctrFixDDBlock_t) : sizeof(ErtsAllctrDDBlock_t));
sz = UNIT_CEILING(sz);
if (sz > allctr->min_block_size)
allctr->min_block_size = sz;
@@ -4325,6 +4333,9 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->fix[i].list = NULL;
allctr->fix[i].allocated = 0;
allctr->fix[i].used = 0;
+#ifdef ERTS_SMP
+ ASSERT(allctr->fix[i].type_size >= sizeof(ErtsAllctrFixDDBlock_t));
+#endif
}
}
@@ -4394,42 +4405,42 @@ erts_alcu_init(AlcUInit_t *init)
* to erts_alcu_test() *
\* */
-unsigned long
-erts_alcu_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_alcu_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x000: return (unsigned long) BLK_SZ((Block_t *) a1);
- case 0x001: return (unsigned long) BLK_UMEM_SZ((Block_t *) a1);
- case 0x002: return (unsigned long) IS_PREV_BLK_FREE((Block_t *) a1);
- case 0x003: return (unsigned long) IS_FREE_BLK((Block_t *) a1);
- case 0x004: return (unsigned long) IS_LAST_BLK((Block_t *) a1);
- case 0x005: return (unsigned long) UMEM2BLK((void *) a1);
- case 0x006: return (unsigned long) BLK2UMEM((Block_t *) a1);
- case 0x007: return (unsigned long) IS_SB_CARRIER((Carrier_t *) a1);
- case 0x008: return (unsigned long) IS_SBC_BLK((Block_t *) a1);
- case 0x009: return (unsigned long) IS_MB_CARRIER((Carrier_t *) a1);
- case 0x00a: return (unsigned long) IS_MSEG_CARRIER((Carrier_t *) a1);
- case 0x00b: return (unsigned long) CARRIER_SZ((Carrier_t *) a1);
- case 0x00c: return (unsigned long) SBC2BLK((Allctr_t *) a1,
+ case 0x000: return (UWord) BLK_SZ((Block_t *) a1);
+ case 0x001: return (UWord) BLK_UMEM_SZ((Block_t *) a1);
+ case 0x002: return (UWord) IS_PREV_BLK_FREE((Block_t *) a1);
+ case 0x003: return (UWord) IS_FREE_BLK((Block_t *) a1);
+ case 0x004: return (UWord) IS_LAST_BLK((Block_t *) a1);
+ case 0x005: return (UWord) UMEM2BLK((void *) a1);
+ case 0x006: return (UWord) BLK2UMEM((Block_t *) a1);
+ case 0x007: return (UWord) IS_SB_CARRIER((Carrier_t *) a1);
+ case 0x008: return (UWord) IS_SBC_BLK((Block_t *) a1);
+ case 0x009: return (UWord) IS_MB_CARRIER((Carrier_t *) a1);
+ case 0x00a: return (UWord) IS_MSEG_CARRIER((Carrier_t *) a1);
+ case 0x00b: return (UWord) CARRIER_SZ((Carrier_t *) a1);
+ case 0x00c: return (UWord) SBC2BLK((Allctr_t *) a1,
(Carrier_t *) a2);
- case 0x00d: return (unsigned long) BLK_TO_SBC((Block_t *) a2);
- case 0x00e: return (unsigned long) MBC_TO_FIRST_BLK((Allctr_t *) a1,
+ case 0x00d: return (UWord) BLK_TO_SBC((Block_t *) a2);
+ case 0x00e: return (UWord) MBC_TO_FIRST_BLK((Allctr_t *) a1,
(Carrier_t *) a2);
- case 0x00f: return (unsigned long) FIRST_BLK_TO_MBC((Allctr_t *) a1,
+ case 0x00f: return (UWord) FIRST_BLK_TO_MBC((Allctr_t *) a1,
(Block_t *) a2);
- case 0x010: return (unsigned long) ((Allctr_t *) a1)->mbc_list.first;
- case 0x011: return (unsigned long) ((Allctr_t *) a1)->mbc_list.last;
- case 0x012: return (unsigned long) ((Allctr_t *) a1)->sbc_list.first;
- case 0x013: return (unsigned long) ((Allctr_t *) a1)->sbc_list.last;
- case 0x014: return (unsigned long) ((Carrier_t *) a1)->next;
- case 0x015: return (unsigned long) ((Carrier_t *) a1)->prev;
- case 0x016: return (unsigned long) ABLK_HDR_SZ;
- case 0x017: return (unsigned long) ((Allctr_t *) a1)->min_block_size;
- case 0x018: return (unsigned long) NXT_BLK((Block_t *) a1);
- case 0x019: return (unsigned long) PREV_BLK((Block_t *) a1);
- case 0x01a: return (unsigned long) IS_MBC_FIRST_BLK((Allctr_t*)a1, (Block_t *) a2);
- case 0x01b: return (unsigned long) sizeof(Unit_t);
- default: ASSERT(0); return ~((unsigned long) 0);
+ case 0x010: return (UWord) ((Allctr_t *) a1)->mbc_list.first;
+ case 0x011: return (UWord) ((Allctr_t *) a1)->mbc_list.last;
+ case 0x012: return (UWord) ((Allctr_t *) a1)->sbc_list.first;
+ case 0x013: return (UWord) ((Allctr_t *) a1)->sbc_list.last;
+ case 0x014: return (UWord) ((Carrier_t *) a1)->next;
+ case 0x015: return (UWord) ((Carrier_t *) a1)->prev;
+ case 0x016: return (UWord) ABLK_HDR_SZ;
+ case 0x017: return (UWord) ((Allctr_t *) a1)->min_block_size;
+ case 0x018: return (UWord) NXT_BLK((Block_t *) a1);
+ case 0x019: return (UWord) PREV_BLK((Block_t *) a1);
+ case 0x01a: return (UWord) IS_MBC_FIRST_BLK((Allctr_t*)a1, (Block_t *) a2);
+ case 0x01b: return (UWord) sizeof(Unit_t);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h
index e0754e7f69..4773598561 100644
--- a/erts/emulator/beam/erl_alloc_util.h
+++ b/erts/emulator/beam/erl_alloc_util.h
@@ -501,7 +501,7 @@ void erts_alcu_stop(Allctr_t *);
void erts_alcu_verify_unused(Allctr_t *);
void erts_alcu_verify_unused_ts(Allctr_t *allctr);
-unsigned long erts_alcu_test(unsigned long, unsigned long, unsigned long);
+UWord erts_alcu_test(UWord, UWord, UWord);
#ifdef DEBUG
int is_sbc_blk(Block_t*);
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c
index 6ce209085c..b916cb6198 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.c
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c
@@ -780,19 +780,19 @@ info_options(Allctr_t *allctr,
* to erts_aoffalc_test() *
\* */
-unsigned long
-erts_aoffalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_aoffalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x500: return (unsigned long) 0; /* IS_AOBF */
- case 0x501: return (unsigned long) ((AOFFAllctr_t *) a1)->mbc_root;
- case 0x502: return (unsigned long) ((AOFF_RBTree_t *) a1)->parent;
- case 0x503: return (unsigned long) ((AOFF_RBTree_t *) a1)->left;
- case 0x504: return (unsigned long) ((AOFF_RBTree_t *) a1)->right;
- case 0x506: return (unsigned long) IS_BLACK((AOFF_RBTree_t *) a1);
- case 0x508: return (unsigned long) 1; /* IS_AOFF */
- case 0x509: return (unsigned long) ((AOFF_RBTree_t *) a1)->max_sz;
- default: ASSERT(0); return ~((unsigned long) 0);
+ case 0x500: return (UWord) 0; /* IS_AOBF */
+ case 0x501: return (UWord) ((AOFFAllctr_t *) a1)->mbc_root;
+ case 0x502: return (UWord) ((AOFF_RBTree_t *) a1)->parent;
+ case 0x503: return (UWord) ((AOFF_RBTree_t *) a1)->left;
+ case 0x504: return (UWord) ((AOFF_RBTree_t *) a1)->right;
+ case 0x506: return (UWord) IS_BLACK((AOFF_RBTree_t *) a1);
+ case 0x508: return (UWord) 1; /* IS_AOFF */
+ case 0x509: return (UWord) ((AOFF_RBTree_t *) a1)->max_sz;
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.h b/erts/emulator/beam/erl_ao_firstfit_alloc.h
index 6fa626f723..21c36c6654 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.h
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.h
@@ -54,7 +54,7 @@ struct AOFFAllctr_t_ {
struct AOFF_RBTree_t_* sbmbc_root;
};
-unsigned long erts_aoffalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_aoffalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_AOFF_ALLOC_IMPL)
&& !defined(ERL_AOFF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c
index 5625622e3f..ed843a51fb 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.c
+++ b/erts/emulator/beam/erl_bestfit_alloc.c
@@ -972,20 +972,20 @@ info_options(Allctr_t *allctr,
* to erts_bfalc_test() *
\* */
-unsigned long
-erts_bfalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_bfalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x200: return (unsigned long) ((BFAllctr_t *) a1)->address_order;
- case 0x201: return (unsigned long) ((BFAllctr_t *) a1)->mbc_root;
- case 0x202: return (unsigned long) ((RBTree_t *) a1)->parent;
- case 0x203: return (unsigned long) ((RBTree_t *) a1)->left;
- case 0x204: return (unsigned long) ((RBTree_t *) a1)->right;
- case 0x205: return (unsigned long) ((RBTreeList_t *) a1)->next;
- case 0x206: return (unsigned long) IS_BLACK((RBTree_t *) a1);
- case 0x207: return (unsigned long) IS_TREE_NODE((RBTree_t *) a1);
- case 0x208: return (unsigned long) 0; /* IS_AOFF */
- default: ASSERT(0); return ~((unsigned long) 0);
+ case 0x200: return (UWord) ((BFAllctr_t *) a1)->address_order;
+ case 0x201: return (UWord) ((BFAllctr_t *) a1)->mbc_root;
+ case 0x202: return (UWord) ((RBTree_t *) a1)->parent;
+ case 0x203: return (UWord) ((RBTree_t *) a1)->left;
+ case 0x204: return (UWord) ((RBTree_t *) a1)->right;
+ case 0x205: return (UWord) ((RBTreeList_t *) a1)->next;
+ case 0x206: return (UWord) IS_BLACK((RBTree_t *) a1);
+ case 0x207: return (UWord) IS_TREE_NODE((RBTree_t *) a1);
+ case 0x208: return (UWord) 0; /* IS_AOFF */
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_bestfit_alloc.h b/erts/emulator/beam/erl_bestfit_alloc.h
index 0c29662852..f2d2f07d7a 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.h
+++ b/erts/emulator/beam/erl_bestfit_alloc.h
@@ -59,7 +59,7 @@ struct BFAllctr_t_ {
int address_order;
};
-unsigned long erts_bfalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_bfalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_BF_ALLOC_IMPL)
&& !defined(ERL_BF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 379d3eecc6..54eefe8d12 100755
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -114,6 +114,9 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE
#ifdef VALGRIND
" [valgrind-compiled]"
#endif
+#ifdef ERTS_FRMPTR
+ " [frame-pointer]"
+#endif
#ifdef USE_DTRACE
" [dtrace]"
#endif
@@ -486,27 +489,6 @@ collect_one_suspend_monitor(ErtsSuspendMonitor *smon, void *vsmicp)
}
}
-
-static void one_link_size(ErtsLink *lnk, void *vpu)
-{
- Uint *pu = vpu;
- *pu += ERTS_LINK_SIZE*sizeof(Uint);
- if(!IS_CONST(lnk->pid))
- *pu += NC_HEAP_SIZE(lnk->pid)*sizeof(Uint);
- if (lnk->type != LINK_NODE && ERTS_LINK_ROOT(lnk) != NULL) {
- erts_doforall_links(ERTS_LINK_ROOT(lnk),&one_link_size,vpu);
- }
-}
-static void one_mon_size(ErtsMonitor *mon, void *vpu)
-{
- Uint *pu = vpu;
- *pu += ERTS_MONITOR_SIZE*sizeof(Uint);
- if(!IS_CONST(mon->pid))
- *pu += NC_HEAP_SIZE(mon->pid)*sizeof(Uint);
- if(!IS_CONST(mon->ref))
- *pu += NC_HEAP_SIZE(mon->ref)*sizeof(Uint);
-}
-
/*
* process_info/[1,2]
*/
@@ -1420,41 +1402,8 @@ process_info_aux(Process *BIF_P,
}
case am_memory: { /* Memory consumed in bytes */
- ErlMessage *mp;
- Uint size = 0;
Uint hsz = 3;
- struct saved_calls *scb;
- size += sizeof(Process);
-
- ERTS_SMP_MSGQ_MV_INQ2PRIVQ(rp);
-
- erts_doforall_links(ERTS_P_LINKS(rp), &one_link_size, &size);
- erts_doforall_monitors(ERTS_P_MONITORS(rp), &one_mon_size, &size);
- size += (rp->heap_sz + rp->mbuf_sz) * sizeof(Eterm);
- if (rp->old_hend && rp->old_heap)
- size += (rp->old_hend - rp->old_heap) * sizeof(Eterm);
-
- size += rp->msg.len * sizeof(ErlMessage);
-
- for (mp = rp->msg.first; mp; mp = mp->next)
- if (mp->data.attached)
- size += erts_msg_attached_data_size(mp)*sizeof(Eterm);
-
- if (rp->arg_reg != rp->def_arg_reg) {
- size += rp->arity * sizeof(rp->arg_reg[0]);
- }
-
- if (rp->psd)
- size += sizeof(ErtsPSD);
-
- scb = ERTS_PROC_GET_SAVED_CALLS_BUF(rp);
- if (scb) {
- size += (sizeof(struct saved_calls)
- + (scb->len-1) * sizeof(scb->ct[0]));
- }
-
- size += erts_dicts_mem_size(rp);
-
+ Uint size = erts_process_memory(rp);
(void) erts_bld_uint(NULL, &hsz, size);
hp = HAlloc(BIF_P, hsz);
res = erts_bld_uint(&hp, NULL, size);
@@ -2096,6 +2045,9 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
#elif defined(ERTS_ENABLE_LOCK_COUNT)
ERTS_DECL_AM(lcnt);
BIF_RET(AM_lcnt);
+#elif defined(ERTS_FRMPTR)
+ ERTS_DECL_AM(frmptr);
+ BIF_RET(AM_frmptr);
#else
BIF_RET(am_opt);
#endif
@@ -2861,12 +2813,10 @@ erts_bld_port_info(Eterm **hpp, ErlOffHeap *ohp, Uint *szp, Port *prt, Eterm ite
included though).
*/
Uint size = 0;
- ErlHeapFragment* bp;
- erts_doforall_links(ERTS_P_LINKS(prt), &one_link_size, &size);
+ erts_doforall_links(ERTS_P_LINKS(prt), &erts_one_link_size, &size);
- for (bp = prt->bp; bp; bp = bp->next)
- size += sizeof(ErlHeapFragment) + (bp->alloc_size - 1)*sizeof(Eterm);
+ size += erts_port_data_size(prt);
if (prt->linebuf)
size += sizeof(LineBuf) + prt->linebuf->ovsiz;
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 44fa41c7b6..109c54fd7f 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -423,57 +423,164 @@ BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2)
}
}
+/*
+ * The erlang:port_set_data()/erlang:port_get_data() operations should
+ * be viewed as operations on a table (inet_db) with data values
+ * associated with port identifier keys. That is, these operations are
+ * *not* signals to/from ports.
+ */
+
+#if (TAG_PRIMARY_IMMED1 & 0x3) == 0
+# error "erlang:port_set_data()/erlang:port_get_data() needs to be rewritten!"
+#endif
+
+typedef struct {
+ ErtsThrPrgrLaterOp later_op;
+ Uint hsize;
+ Eterm data;
+ ErlOffHeap off_heap;
+ Eterm heap[1];
+} ErtsPortDataHeap;
-BIF_RETTYPE erts_internal_port_set_data_2(BIF_ALIST_2)
+static void
+free_port_data_heap(void *vpdhp)
{
- Eterm ref;
+ erts_cleanup_offheap(&((ErtsPortDataHeap *) vpdhp)->off_heap);
+ erts_free(ERTS_ALC_T_PORT_DATA_HEAP, vpdhp);
+}
+
+static ERTS_INLINE void
+cleanup_old_port_data(erts_aint_t data)
+{
+ if ((data & 0x3) != 0) {
+ ASSERT(is_immed((Eterm) data));
+ }
+ else {
+#ifdef ERTS_SMP
+ ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
+ size_t size;
+ ERTS_SMP_DATA_DEPENDENCY_READ_MEMORY_BARRIER;
+ size = sizeof(ErtsPortDataHeap) + pdhp->hsize*(sizeof(Eterm) - 1);
+ erts_schedule_thr_prgr_later_cleanup_op(free_port_data_heap,
+ (void *) pdhp,
+ &pdhp->later_op,
+ size);
+#else
+ free_port_data_heap((void *) data);
+#endif
+ }
+}
+
+void
+erts_init_port_data(Port *prt)
+{
+ erts_smp_atomic_init_nob(&prt->data, (erts_aint_t) am_undefined);
+}
+
+void
+erts_cleanup_port_data(Port *prt)
+{
+ ASSERT(erts_atomic32_read_nob(&prt->state) & ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ cleanup_old_port_data(erts_smp_atomic_read_nob(&prt->data));
+ erts_smp_atomic_set_nob(&prt->data, (erts_aint_t) THE_NON_VALUE);
+}
+
+Uint
+erts_port_data_size(Port *prt)
+{
+ erts_aint_t data = erts_smp_atomic_read_ddrb(&prt->data);
+
+ if ((data & 0x3) != 0) {
+ ASSERT(is_immed((Eterm) (UWord) data));
+ return (Uint) 0;
+ }
+ else {
+ ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
+ return (Uint) sizeof(ErtsPortDataHeap) + pdhp->hsize*(sizeof(Eterm)-1);
+ }
+}
+
+ErlOffHeap *
+erts_port_data_offheap(Port *prt)
+{
+ erts_aint_t data = erts_smp_atomic_read_ddrb(&prt->data);
+
+ if ((data & 0x3) != 0) {
+ ASSERT(is_immed((Eterm) (UWord) data));
+ return NULL;
+ }
+ else {
+ ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
+ return &pdhp->off_heap;
+ }
+}
+
+BIF_RETTYPE port_set_data_2(BIF_ALIST_2)
+{
+ /*
+ * This is not a signal. See comment above.
+ */
+ erts_aint_t data;
Port* prt;
prt = lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_badarg);
+ BIF_ERROR(BIF_P, BADARG);
- switch (erts_port_set_data(BIF_P, prt, BIF_ARG_2, &ref)) {
- case ERTS_PORT_OP_CALLER_EXIT:
- case ERTS_PORT_OP_BADARG:
- case ERTS_PORT_OP_DROPPED:
- BIF_RET(am_badarg);
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ref(ref));
- BIF_RET(ref);
- case ERTS_PORT_OP_DONE:
- BIF_RET(am_true);
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_set_data() result");
- BIF_RET(am_internal_error);
+ if (is_immed(BIF_ARG_2)) {
+ data = (erts_aint_t) BIF_ARG_2;
+ ASSERT((data & 0x3) != 0);
}
+ else {
+ ErtsPortDataHeap *pdhp;
+ Uint hsize;
+ Eterm *hp;
+
+ hsize = size_object(BIF_ARG_2);
+ pdhp = erts_alloc(ERTS_ALC_T_PORT_DATA_HEAP,
+ sizeof(ErtsPortDataHeap) + hsize*(sizeof(Eterm)-1));
+ hp = &pdhp->heap[0];
+ pdhp->off_heap.first = NULL;
+ pdhp->off_heap.overhead = 0;
+ pdhp->data = copy_struct(BIF_ARG_2, hsize, &hp, &pdhp->off_heap);
+ data = (erts_aint_t) pdhp;
+ ASSERT((data & 0x3) == 0);
+ }
+
+ data = erts_smp_atomic_xchg_wb(&prt->data, data);
+
+ cleanup_old_port_data(data);
+
+ BIF_RET(am_true);
}
-BIF_RETTYPE erts_internal_port_get_data_1(BIF_ALIST_1)
+BIF_RETTYPE port_get_data_1(BIF_ALIST_1)
{
- Eterm retval;
+ /*
+ * This is not a signal. See comment above.
+ */
+ Eterm res;
+ erts_aint_t data;
Port* prt;
prt = lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_badarg);
+ BIF_ERROR(BIF_P, BADARG);
- switch (erts_port_get_data(BIF_P, prt, &retval)) {
- case ERTS_PORT_OP_CALLER_EXIT:
- case ERTS_PORT_OP_BADARG:
- case ERTS_PORT_OP_DROPPED:
- BIF_RET(am_badarg);
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ref(retval));
- BIF_RET(retval);
- case ERTS_PORT_OP_DONE:
- ASSERT(is_not_internal_ref(retval));
- BIF_RET(retval);
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_get_data() result");
- BIF_RET(am_internal_error);
+ data = erts_smp_atomic_read_ddrb(&prt->data);
+
+ if ((data & 0x3) != 0) {
+ res = (Eterm) (UWord) data;
+ ASSERT(is_immed(res));
+ }
+ else {
+ ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
+ Eterm *hp = HAlloc(BIF_P, pdhp->hsize);
+ res = copy_struct(pdhp->data, pdhp->hsize, &hp, &MSO(BIF_P));
}
+
+ BIF_RET(res);
}
/*
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 41c98bbffb..559cb3efa1 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -1224,9 +1224,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
match_spec_meta = NIL;
}
if (r & FUNC_TRACE_COUNT_TRACE) {
- c = count < 0 ?
- erts_make_integer(-count-1, p) :
- erts_make_integer(count, p);
+ c = erts_make_integer(count, p);
}
if (r & FUNC_TRACE_TIME_TRACE) {
ct = call_time;
diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c
index c2088929e9..79d8b40f8c 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.c
+++ b/erts/emulator/beam/erl_goodfit_alloc.c
@@ -589,16 +589,16 @@ info_options(Allctr_t *allctr,
* to erts_gfalc_test() *
\* */
-unsigned long
-erts_gfalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_gfalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x100: return (unsigned long) BKT_IX((GFAllctr_t *) a1, (Uint) a2);
- case 0x101: return (unsigned long) BKT_MIN_SZ((GFAllctr_t *) a1, (int) a2);
- case 0x102: return (unsigned long) NO_OF_BKTS;
- case 0x103: return (unsigned long)
+ case 0x100: return (UWord) BKT_IX((GFAllctr_t *) a1, (Uint) a2);
+ case 0x101: return (UWord) BKT_MIN_SZ((GFAllctr_t *) a1, (int) a2);
+ case 0x102: return (UWord) NO_OF_BKTS;
+ case 0x103: return (UWord)
find_bucket(&((GFAllctr_t *) a1)->bucket_mask, (int) a2);
- default: ASSERT(0); return ~((unsigned long) 0);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_goodfit_alloc.h b/erts/emulator/beam/erl_goodfit_alloc.h
index a554a6f466..11bef77e7f 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.h
+++ b/erts/emulator/beam/erl_goodfit_alloc.h
@@ -82,7 +82,7 @@ struct GFAllctr_t_ {
};
-unsigned long erts_gfalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_gfalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_GF_ALLOC_IMPL)
&& !defined(ERL_GF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_instrument.c b/erts/emulator/beam/erl_instrument.c
index b5b245288b..1aea3f65bc 100644
--- a/erts/emulator/beam/erl_instrument.c
+++ b/erts/emulator/beam/erl_instrument.c
@@ -271,6 +271,18 @@ stat_upd_realloc(ErtsAlcType_t n, Uint size, Uint old_size)
* stat instrumentation callback functions
*/
+static void stat_pre_lock(void)
+{
+ erts_mtx_lock(&instr_mutex);
+}
+
+static void stat_pre_unlock(void)
+{
+ erts_mtx_unlock(&instr_mutex);
+}
+
+static ErtsAllocatorWrapper_t instr_wrapper;
+
static void *
stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
{
@@ -278,7 +290,9 @@ stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
Uint ssize;
void *res;
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_mutex);
+ }
ssize = size + STAT_BLOCK_HEADER_SIZE;
res = (*real_af->alloc)(n, real_af->extra, ssize);
@@ -293,7 +307,9 @@ stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
res = (void *) ((StatBlock_t *) res)->mem;
}
- erts_mtx_unlock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ }
return res;
}
@@ -307,7 +323,9 @@ stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
void *sptr;
void *res;
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_mutex);
+ }
if (ptr) {
sptr = (void *) (((char *) ptr) - STAT_BLOCK_HEADER_SIZE);
@@ -329,7 +347,9 @@ stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
res = (void *) ((StatBlock_t *) res)->mem;
}
- erts_mtx_unlock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ }
return res;
}
@@ -340,7 +360,9 @@ stat_free(ErtsAlcType_t n, void *extra, void *ptr)
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *sptr;
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_mutex);
+ }
if (ptr) {
sptr = (void *) (((char *) ptr) - STAT_BLOCK_HEADER_SIZE);
@@ -352,7 +374,9 @@ stat_free(ErtsAlcType_t n, void *extra, void *ptr)
(*real_af->free)(n, real_af->extra, sptr);
- erts_mtx_unlock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ }
}
@@ -360,6 +384,18 @@ stat_free(ErtsAlcType_t n, void *extra, void *ptr)
* map stat instrumentation callback functions
*/
+static void map_stat_pre_lock(void)
+{
+ erts_mtx_lock(&instr_x_mutex);
+ erts_mtx_lock(&instr_mutex);
+}
+
+static void map_stat_pre_unlock(void)
+{
+ erts_mtx_unlock(&instr_mutex);
+ erts_mtx_unlock(&instr_x_mutex);
+}
+
static void *
map_stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
{
@@ -367,7 +403,9 @@ map_stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
Uint msize;
void *res;
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_mutex);
+ }
msize = size + MAP_STAT_BLOCK_HEADER_SIZE;
res = (*real_af->alloc)(n, real_af->extra, msize);
@@ -388,7 +426,9 @@ map_stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
res = (void *) mb->mem;
}
- erts_mtx_unlock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ }
return res;
}
@@ -402,8 +442,10 @@ map_stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
void *mptr;
void *res;
- erts_mtx_lock(&instr_x_mutex);
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_x_mutex);
+ erts_mtx_lock(&instr_mutex);
+ }
if (ptr) {
mptr = (void *) (((char *) ptr) - MAP_STAT_BLOCK_HEADER_SIZE);
@@ -449,9 +491,10 @@ map_stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
res = (void *) mb->mem;
}
-
- erts_mtx_unlock(&instr_mutex);
- erts_mtx_unlock(&instr_x_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ erts_mtx_unlock(&instr_x_mutex);
+ }
return res;
}
@@ -462,8 +505,10 @@ map_stat_free(ErtsAlcType_t n, void *extra, void *ptr)
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *mptr;
- erts_mtx_lock(&instr_x_mutex);
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_x_mutex);
+ erts_mtx_lock(&instr_mutex);
+ }
if (ptr) {
MapStatBlock_t *mb;
@@ -486,8 +531,10 @@ map_stat_free(ErtsAlcType_t n, void *extra, void *ptr)
(*real_af->free)(n, real_af->extra, mptr);
- erts_mtx_unlock(&instr_mutex);
- erts_mtx_unlock(&instr_x_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ erts_mtx_unlock(&instr_x_mutex);
+ }
}
@@ -496,8 +543,10 @@ static void dump_memory_map_to_stream(FILE *fp)
ErtsAlcType_t n;
MapStatBlock_t *bp;
int lock = !ERTS_IS_CRASH_DUMPING;
- if (lock)
+ if (lock) {
+ ASSERT(!erts_is_allctr_wrapper_prelocked());
erts_mtx_lock(&instr_mutex);
+ }
/* Write header */
@@ -1155,6 +1204,7 @@ erts_instr_get_type_info(Process *proc)
Uint
erts_instr_init(int stat, int map_stat)
{
+ Uint extra_sz;
int i;
am_tot = NULL;
@@ -1208,7 +1258,9 @@ erts_instr_init(int stat, int map_stat)
erts_allctrs[i].free = map_stat_free;
erts_allctrs[i].extra = (void *) &real_allctrs[i];
}
- return MAP_STAT_BLOCK_HEADER_SIZE;
+ instr_wrapper.lock = map_stat_pre_lock;
+ instr_wrapper.unlock = map_stat_pre_unlock;
+ extra_sz = MAP_STAT_BLOCK_HEADER_SIZE;
}
else {
erts_instr_stat = 1;
@@ -1220,8 +1272,11 @@ erts_instr_init(int stat, int map_stat)
erts_allctrs[i].free = stat_free;
erts_allctrs[i].extra = (void *) &real_allctrs[i];
}
- return STAT_BLOCK_HEADER_SIZE;
+ instr_wrapper.lock = stat_pre_lock;
+ instr_wrapper.unlock = stat_pre_unlock;
+ extra_sz = STAT_BLOCK_HEADER_SIZE;
}
-
+ erts_allctr_wrapper_prelock_init(&instr_wrapper);
+ return extra_sz;
}
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 69bb4be717..a1d270adba 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -143,6 +143,8 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "ptimer_pre_alloc_lock", "address", },
{ "btm_pre_alloc_lock", NULL, },
{ "dist_entry_out_queue", "address" },
+ { "port_sched_lock", "port_id" },
+ { "port_table", NULL },
#endif
{ "mtrace_op", NULL },
{ "instr_x", NULL },
@@ -154,10 +156,8 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "pmmap", NULL },
#endif
#ifdef ERTS_SMP
- { "port_sched_lock", "port_id" },
{ "port_task_pre_alloc_lock", "address" },
{ "proclist_pre_alloc_lock", "address" },
- { "port_table", NULL },
{ "xports_list_pre_alloc_lock", "address" },
{ "inet_buffer_stack_lock", NULL },
{ "gc_info", NULL },
diff --git a/erts/emulator/beam/erl_monitors.c b/erts/emulator/beam/erl_monitors.c
index 70e592cc5f..244a2b26db 100644
--- a/erts/emulator/beam/erl_monitors.c
+++ b/erts/emulator/beam/erl_monitors.c
@@ -1024,3 +1024,23 @@ Eterm erts_debug_dump_links_1(BIF_ALIST_1)
}
}
}
+
+void erts_one_link_size(ErtsLink *lnk, void *vpu)
+{
+ Uint *pu = vpu;
+ *pu += ERTS_LINK_SIZE*sizeof(Uint);
+ if(!IS_CONST(lnk->pid))
+ *pu += NC_HEAP_SIZE(lnk->pid)*sizeof(Uint);
+ if (lnk->type != LINK_NODE && ERTS_LINK_ROOT(lnk) != NULL) {
+ erts_doforall_links(ERTS_LINK_ROOT(lnk),&erts_one_link_size,vpu);
+ }
+}
+void erts_one_mon_size(ErtsMonitor *mon, void *vpu)
+{
+ Uint *pu = vpu;
+ *pu += ERTS_MONITOR_SIZE*sizeof(Uint);
+ if(!IS_CONST(mon->pid))
+ *pu += NC_HEAP_SIZE(mon->pid)*sizeof(Uint);
+ if(!IS_CONST(mon->ref))
+ *pu += NC_HEAP_SIZE(mon->ref)*sizeof(Uint);
+}
diff --git a/erts/emulator/beam/erl_monitors.h b/erts/emulator/beam/erl_monitors.h
index 6a360a2336..fb11dbbd22 100644
--- a/erts/emulator/beam/erl_monitors.h
+++ b/erts/emulator/beam/erl_monitors.h
@@ -170,6 +170,8 @@ ErtsSuspendMonitor *erts_lookup_suspend_monitor(ErtsSuspendMonitor *root,
Eterm pid);
void erts_delete_suspend_monitor(ErtsSuspendMonitor **root, Eterm pid);
void erts_init_monitors(void);
+void erts_one_link_size(ErtsLink *lnk, void *vpu);
+void erts_one_mon_size(ErtsMonitor *mon, void *vpu);
#define erts_doforall_monitors erts_sweep_monitors
#define erts_doforall_links erts_sweep_links
diff --git a/erts/emulator/beam/erl_mtrace.c b/erts/emulator/beam/erl_mtrace.c
index e538ba30c2..c8bb126687 100644
--- a/erts/emulator/beam/erl_mtrace.c
+++ b/erts/emulator/beam/erl_mtrace.c
@@ -222,6 +222,8 @@ static byte *tracep;
static byte *endp;
static SysTimeval last_tv;
+static ErtsAllocatorWrapper_t mtrace_wrapper;
+
#if ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0
#error ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0
#endif
@@ -555,6 +557,8 @@ write_trace_header(char *nodename, char *pid, char *hostname)
return 1;
}
+static void mtrace_pre_lock(void);
+static void mtrace_pre_unlock(void);
static void *mtrace_alloc(ErtsAlcType_t, void *, Uint);
static void *mtrace_realloc(ErtsAlcType_t, void *, void *, Uint);
static void mtrace_free(ErtsAlcType_t, void *, void *);
@@ -635,12 +639,16 @@ erts_mtrace_install_wrapper_functions(void)
erts_allctrs[i].free = mtrace_free;
erts_allctrs[i].extra = (void *) &real_allctrs[i];
}
+ mtrace_wrapper.lock = mtrace_pre_lock;
+ mtrace_wrapper.unlock = mtrace_pre_unlock;
+ erts_allctr_wrapper_prelock_init(&mtrace_wrapper);
}
}
void
erts_mtrace_stop(void)
{
+ ASSERT(!erts_is_allctr_wrapper_prelocked());
erts_mtx_lock(&mtrace_op_mutex);
erts_mtx_lock(&mtrace_buf_mutex);
if (erts_mtrace_enabled) {
@@ -677,6 +685,7 @@ erts_mtrace_stop(void)
void
erts_mtrace_exit(Uint32 exit_value)
{
+ ASSERT(!erts_is_allctr_wrapper_prelocked());
erts_mtx_lock(&mtrace_op_mutex);
erts_mtx_lock(&mtrace_buf_mutex);
if (erts_mtrace_enabled) {
@@ -935,18 +944,33 @@ write_free_entry(byte tag,
erts_mtx_unlock(&mtrace_buf_mutex);
}
+static void mtrace_pre_lock(void)
+{
+ erts_mtx_lock(&mtrace_op_mutex);
+}
+
+static void mtrace_pre_unlock(void)
+{
+ erts_mtx_unlock(&mtrace_op_mutex);
+}
+
+
static void *
mtrace_alloc(ErtsAlcType_t n, void *extra, Uint size)
{
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *res;
- erts_mtx_lock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&mtrace_op_mutex);
+ }
res = (*real_af->alloc)(n, real_af->extra, size);
write_alloc_entry(ERTS_MT_ALLOC_BDY_TAG, res, n, 0, size);
- erts_mtx_unlock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&mtrace_op_mutex);
+ }
return res;
}
@@ -957,12 +981,16 @@ mtrace_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *res;
- erts_mtx_lock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&mtrace_op_mutex);
+ }
res = (*real_af->realloc)(n, real_af->extra, ptr, size);
write_realloc_entry(ERTS_MT_REALLOC_BDY_TAG, res, n, 0, ptr, size);
- erts_mtx_unlock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&mtrace_op_mutex);
+ }
return res;
@@ -973,10 +1001,14 @@ mtrace_free(ErtsAlcType_t n, void *extra, void *ptr)
{
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
- erts_mtx_lock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&mtrace_op_mutex);
+ }
(*real_af->free)(n, real_af->extra, ptr);
- write_free_entry(ERTS_MT_FREE_BDY_TAG, n, 0, ptr);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ write_free_entry(ERTS_MT_FREE_BDY_TAG, n, 0, ptr);
+ }
erts_mtx_unlock(&mtrace_op_mutex);
}
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index ebfba065d1..e688e55c88 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -1371,6 +1371,7 @@ setup_reference_table(void)
/* Insert all ports */
max = erts_ptab_max(&erts_port);
for (i = 0; i < max; i++) {
+ ErlOffHeap *ohp;
erts_aint32_t state;
Port *prt;
@@ -1389,8 +1390,9 @@ setup_reference_table(void)
if (ERTS_P_MONITORS(prt))
insert_monitors(ERTS_P_MONITORS(prt), prt->common.id);
/* Insert port data */
- for(hfp = prt->bp; hfp; hfp = hfp->next)
- insert_offheap(&(hfp->off_heap), HEAP_REF, prt->common.id);
+ ohp = erts_port_data_offheap(prt);
+ if (ohp)
+ insert_offheap(ohp, HEAP_REF, prt->common.id);
/* Insert controller */
if (prt->dist_entry)
insert_dist_entry(prt->dist_entry,
diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h
index 377aa72ed5..ad3f104a68 100644
--- a/erts/emulator/beam/erl_port.h
+++ b/erts/emulator/beam/erl_port.h
@@ -167,8 +167,7 @@ struct _erl_drv_port {
#endif
erts_atomic_t connected; /* A connected process */
Eterm caller; /* Current caller. */
- Eterm data; /* Data associated with port. */
- ErlHeapFragment* bp; /* Heap fragment holding data (NULL if imm data). */
+ erts_smp_atomic_t data; /* Data associated with port. */
Uint bytes_in; /* Number of bytes read */
Uint bytes_out; /* Number of bytes written */
@@ -189,6 +188,12 @@ struct _erl_drv_port {
int reds; /* Only used while executing driver callbacks */
};
+
+void erts_init_port_data(Port *);
+void erts_cleanup_port_data(Port *);
+Uint erts_port_data_size(Port *);
+ErlOffHeap *erts_port_data_offheap(Port *);
+
#define ERTS_PORT_GET_CONNECTED(PRT) \
((Eterm) erts_atomic_read_nob(&(PRT)->connected))
#define ERTS_PORT_SET_CONNECTED(PRT, PID) \
@@ -326,8 +331,6 @@ extern erts_smp_atomic_t erts_bytes_in; /* no bytes sent into the system */
#define ERTS_PORT_REDS_CONTROL (CONTEXT_REDS/100)
#define ERTS_PORT_REDS_CALL (CONTEXT_REDS/50)
#define ERTS_PORT_REDS_INFO (CONTEXT_REDS/100)
-#define ERTS_PORT_REDS_SET_DATA (CONTEXT_REDS/100)
-#define ERTS_PORT_REDS_GET_DATA (CONTEXT_REDS/100)
#define ERTS_PORT_REDS_TERMINATE (CONTEXT_REDS/50)
void print_port_info(Port *, int, void *);
@@ -794,8 +797,6 @@ struct binary;
#define ERTS_P2P_SIG_TYPE_INFO 7
#define ERTS_P2P_SIG_TYPE_LINK 8
#define ERTS_P2P_SIG_TYPE_UNLINK 9
-#define ERTS_P2P_SIG_TYPE_SET_DATA 10
-#define ERTS_P2P_SIG_TYPE_GET_DATA 11
#define ERTS_P2P_SIG_TYPE_BITS 4
#define ERTS_P2P_SIG_TYPE_MASK \
@@ -810,6 +811,7 @@ struct binary;
#define ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT ERTS_P2P_SIG_DATA_FLG(4)
#define ERTS_P2P_SIG_DATA_FLG_BROKEN_LINK ERTS_P2P_SIG_DATA_FLG(5)
#define ERTS_P2P_SIG_DATA_FLG_SCHED ERTS_P2P_SIG_DATA_FLG(6)
+#define ERTS_P2P_SIG_DATA_FLG_ASYNC ERTS_P2P_SIG_DATA_FLG(7)
struct ErtsProc2PortSigData_ {
int flags;
@@ -856,10 +858,6 @@ struct ErtsProc2PortSigData_ {
struct {
Eterm from;
} unlink;
- struct {
- ErlHeapFragment *bp;
- Eterm data;
- } set_data;
} u;
} ;
@@ -919,6 +917,7 @@ erts_schedule_proc2port_signal(Process *,
Eterm *,
ErtsProc2PortSigData *,
int,
+ ErtsPortTaskHandle *,
ErtsProc2PortSigCallback);
int erts_deliver_port_exit(Port *, Eterm, Eterm, int);
@@ -932,6 +931,7 @@ int erts_deliver_port_exit(Port *, Eterm, Eterm, int);
#define ERTS_PORT_SIG_FLG_BROKEN_LINK ERTS_P2P_SIG_DATA_FLG_BROKEN_LINK
#define ERTS_PORT_SIG_FLG_BAD_OUTPUT ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT
#define ERTS_PORT_SIG_FLG_FORCE_SCHED ERTS_P2P_SIG_DATA_FLG_SCHED
+#define ERTS_PORT_SIG_FLG_ASYNC ERTS_P2P_SIG_DATA_FLG_ASYNC
/* ERTS_PORT_SIG_FLG_FORCE_IMM_CALL only when crash dumping... */
#define ERTS_PORT_SIG_FLG_FORCE_IMM_CALL ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT
@@ -953,7 +953,5 @@ ErtsPortOpResult erts_port_unlink(Process *, Port *, Eterm, Eterm *);
ErtsPortOpResult erts_port_control(Process *, Port *, unsigned int, Eterm, Eterm *);
ErtsPortOpResult erts_port_call(Process *, Port *, unsigned int, Eterm, Eterm *);
ErtsPortOpResult erts_port_info(Process *, Port *, Eterm, Eterm *);
-ErtsPortOpResult erts_port_set_data(Process *, Port *, Eterm, Eterm *);
-ErtsPortOpResult erts_port_get_data(Process *, Port *, Eterm *);
#endif
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index 0ed08bee01..53cb01a8c6 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -552,6 +552,19 @@ set_handle(ErtsPortTask *ptp, ErtsPortTaskHandle *pthp)
}
}
+static ERTS_INLINE void
+set_tmp_handle(ErtsPortTask *ptp, ErtsPortTaskHandle *pthp)
+{
+ ptp->u.alive.handle = NULL;
+ if (pthp) {
+ /*
+ * IMPORTANT! Task either need to be aborted, or task handle
+ * need to be detached before thread progress has been made.
+ */
+ erts_smp_atomic_set_relb(pthp, (erts_aint_t) ptp);
+ }
+}
+
/*
* Busy port queue management
@@ -1182,6 +1195,13 @@ erl_drv_consume_timeslice(ErlDrvPort dprt, int percent)
return 1;
}
+void
+erts_port_task_tmp_handle_detach(ErtsPortTaskHandle *pthp)
+{
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_lc_is_delaying());
+ reset_port_task_handle(pthp);
+}
+
/*
* Abort a scheduled task.
*/
@@ -1206,7 +1226,7 @@ erts_port_task_abort(ErtsPortTaskHandle *pthp)
ERTS_SMP_READ_MEMORY_BARRIER;
old_state = erts_smp_atomic32_read_nob(&ptp->state);
if (old_state == ERTS_PT_STATE_SCHEDULED) {
- ASSERT(saved_pthp == pthp);
+ ASSERT(!saved_pthp || saved_pthp == pthp);
}
#endif
@@ -1227,9 +1247,6 @@ erts_port_task_abort(ErtsPortTaskHandle *pthp)
&erts_port_task_outstanding_io_tasks) > 0);
erts_smp_atomic_dec_relb(&erts_port_task_outstanding_io_tasks);
break;
- case ERTS_PORT_TASK_PROC_SIG:
- ERTS_INTERNAL_ERROR("Aborted process to port signal");
- break;
default:
break;
}
@@ -1404,7 +1421,6 @@ erts_port_task_schedule(Eterm id,
}
case ERTS_PORT_TASK_PROC_SIG: {
va_list argp;
- ASSERT(!pthp);
va_start(argp, type);
sigdp = va_arg(argp, ErtsProc2PortSigData *);
ptp = p2p_sig_data_to_task(sigdp);
@@ -1412,7 +1428,7 @@ erts_port_task_schedule(Eterm id,
ptp->u.alive.flags |= va_arg(argp, int);
va_end(argp);
if (!(ptp->u.alive.flags & ERTS_PT_FLG_NOSUSPEND))
- set_handle(ptp, pthp);
+ set_tmp_handle(ptp, pthp);
else {
ns_pthlp = erts_alloc(ERTS_ALC_T_PT_HNDL_LIST,
sizeof(ErtsPortTaskHandleList));
diff --git a/erts/emulator/beam/erl_port_task.h b/erts/emulator/beam/erl_port_task.h
index ae6cd69ae2..d35a15c27b 100644
--- a/erts/emulator/beam/erl_port_task.h
+++ b/erts/emulator/beam/erl_port_task.h
@@ -243,7 +243,9 @@ int erts_port_task_execute(ErtsRunQueue *, Port **);
void erts_port_task_init(void);
#endif
+void erts_port_task_tmp_handle_detach(ErtsPortTaskHandle *);
int erts_port_task_abort(ErtsPortTaskHandle *);
+
void erts_port_task_abort_nosuspend_tasks(Port *);
int erts_port_task_schedule(Eterm,
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 8bf481dbff..7415a5721f 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -2625,6 +2625,8 @@ set_no_active_runqs(int active)
erts_aint32_t exp = erts_smp_atomic32_read_nob(&balance_info.no_runqs);
while (1) {
erts_aint32_t act, new;
+ if ((exp & ERTS_NO_RUNQS_MASK) == active)
+ break;
new = exp & (ERTS_NO_RUNQS_MASK << ERTS_NO_USED_RUNQS_SHIFT);
new |= active & ERTS_NO_RUNQS_MASK;
act = erts_smp_atomic32_cmpxchg_nob(&balance_info.no_runqs, new, exp);
@@ -3171,9 +3173,6 @@ evacuate_run_queue(ErtsRunQueue *rq,
if (notify)
smp_notify_inc_runq(to_rq);
}
-
- if (ERTS_EMPTY_RUNQ(rq))
- empty_runq(rq);
}
static int
@@ -4067,9 +4066,8 @@ static void
change_no_used_runqs(int used)
{
ErtsMigrationPaths *new_mpaths, *old_mpaths;
- int active, qix;
+ int qix;
erts_smp_mtx_lock(&balance_info.update_mtx);
- get_no_runqs(&active, NULL);
set_no_used_runqs(used);
old_mpaths = erts_get_migration_paths_managed();
@@ -4672,6 +4670,8 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online)
esdp->reductions = 0;
init_sched_wall_time(&esdp->sched_wall_time);
+
+ erts_port_task_handle_init(&esdp->nosuspend_port_task_handle);
}
init_misc_aux_work();
@@ -4697,7 +4697,7 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online)
schdlr_sspnd.msb.ongoing = 0;
erts_smp_atomic32_init_nob(&schdlr_sspnd.active, no_schedulers);
schdlr_sspnd.msb.procs = NULL;
- init_no_runqs(no_schedulers, no_schedulers_online);
+ init_no_runqs(no_schedulers_online, no_schedulers_online);
balance_info.last_active_runqs = no_schedulers;
erts_smp_mtx_init(&balance_info.update_mtx, "migration_info_update");
balance_info.forced_check_balance = 0;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 3d3579fa7e..5a1f6bbe8d 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -507,6 +507,7 @@ struct ErtsSchedulerData_ {
Uint64 reductions;
ErtsSchedWallTime sched_wall_time;
+ ErtsPortTaskHandle nosuspend_port_task_handle;
#ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
erts_alloc_verify_func_t verify_unused_temp_alloc;
@@ -1421,6 +1422,8 @@ Eterm erts_debug_reader_groups_map(Process *c_p, int groups);
Uint erts_debug_nbalance(void);
int erts_debug_wait_deallocations(Process *c_p);
+Uint erts_process_memory(Process *c_p);
+
#ifdef ERTS_SMP
# define ERTS_GET_SCHEDULER_DATA_FROM_PROC(PROC) ((PROC)->scheduler_data)
# define ERTS_PROC_GET_SCHDATA(PROC) ((PROC)->scheduler_data)
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index a93229c473..6cd0d23b97 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -76,6 +76,43 @@ erts_deep_process_dump(int to, void *to_arg)
dump_binaries(to, to_arg, all_binaries);
}
+Uint erts_process_memory(Process *p) {
+ ErlMessage *mp;
+ Uint size = 0;
+ struct saved_calls *scb;
+ size += sizeof(Process);
+
+ ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p);
+
+ erts_doforall_links(ERTS_P_LINKS(p), &erts_one_link_size, &size);
+ erts_doforall_monitors(ERTS_P_MONITORS(p), &erts_one_mon_size, &size);
+ size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm);
+ if (p->old_hend && p->old_heap)
+ size += (p->old_hend - p->old_heap) * sizeof(Eterm);
+
+ size += p->msg.len * sizeof(ErlMessage);
+
+ for (mp = p->msg.first; mp; mp = mp->next)
+ if (mp->data.attached)
+ size += erts_msg_attached_data_size(mp)*sizeof(Eterm);
+
+ if (p->arg_reg != p->def_arg_reg) {
+ size += p->arity * sizeof(p->arg_reg[0]);
+ }
+
+ if (p->psd)
+ size += sizeof(ErtsPSD);
+
+ scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p);
+ if (scb) {
+ size += (sizeof(struct saved_calls)
+ + (scb->len-1) * sizeof(scb->ct[0]));
+ }
+
+ size += erts_dicts_mem_size(p);
+ return size;
+}
+
static void
dump_process_info(int to, void *to_arg, Process *p)
{
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 5ce0d97c74..8420cfae24 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -3147,17 +3147,6 @@ encode_size_struct2(ErtsAtomCacheMap *acmp, Eterm obj, unsigned dflags)
return result;
}
-static int is_valid_utf8_atom(byte* bytes, Uint nbytes)
-{
- byte* err_pos;
- Uint num_chars;
-
- /*SVERK Do we really need to validate correct utf8? */
- return nbytes <= MAX_ATOM_SZ_LIMIT
- && erts_analyze_utf8(bytes, nbytes, &err_pos, &num_chars, NULL) == ERTS_UTF8_OK
- && num_chars <= MAX_ATOM_CHARACTERS;
-}
-
static Sint
decoded_size(byte *ep, byte* endp, int internal_tags)
{
@@ -3235,7 +3224,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
CHKSIZE(2);
n = get_int16(ep);
ep += 2;
- if (!is_valid_utf8_atom(ep, n)) {
+ if (n > MAX_ATOM_SZ_LIMIT) {
return -1;
}
SKIP(n+atom_extra_skip);
@@ -3254,7 +3243,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
CHKSIZE(1);
n = get_int8(ep);
ep++;
- if (!is_valid_utf8_atom(ep, n)) {
+ if (n > MAX_ATOM_SZ_LIMIT) {
return -1;
}
SKIP(n+atom_extra_skip);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 7cadd4aaad..b6b7b47bd6 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -364,9 +364,8 @@ static Port *create_port(char *name,
ERTS_P_LINKS(prt) = NULL;
ERTS_P_MONITORS(prt) = NULL;
prt->linebuf = NULL;
- prt->bp = NULL;
prt->suspended = NULL;
- prt->data = am_undefined;
+ erts_init_port_data(prt);
prt->port_data_lock = NULL;
prt->control_flags = 0;
prt->bytes_in = 0;
@@ -1442,6 +1441,7 @@ erts_schedule_proc2port_signal(Process *c_p,
Eterm *refp,
ErtsProc2PortSigData *sigdp,
int task_flags,
+ ErtsPortTaskHandle *pthp,
ErtsProc2PortSigCallback callback)
{
int sched_res;
@@ -1491,7 +1491,7 @@ erts_schedule_proc2port_signal(Process *c_p,
/* Schedule port close call for later execution... */
sched_res = erts_port_task_schedule(prt->common.id,
- NULL,
+ pthp,
ERTS_PORT_TASK_PROC_SIG,
sigdp,
callback,
@@ -1629,6 +1629,7 @@ bad_port_signal(Process *c_p,
refp,
sigdp,
0,
+ NULL,
port_badsig);
}
@@ -1838,8 +1839,11 @@ erts_port_output(Process *c_p,
ErlIOVec *evp = NULL;
char *buf = NULL;
int force_immediate_call = (flags & ERTS_PORT_SIG_FLG_FORCE_IMM_CALL);
+ int async_nosuspend;
+ ErtsPortTaskHandle *ns_pthp;
ASSERT((flags & ~(ERTS_PORT_SIG_FLG_BANG_OP
+ | ERTS_PORT_SIG_FLG_ASYNC
| ERTS_PORT_SIG_FLG_NOSUSPEND
| ERTS_PORT_SIG_FLG_FORCE
| ERTS_PORT_SIG_FLG_FORCE_IMM_CALL)) == 0);
@@ -1861,6 +1865,12 @@ erts_port_output(Process *c_p,
? ERTS_PORT_OP_DROPPED
: ERTS_PORT_OP_BUSY);
+ async_nosuspend = ((flags & (ERTS_PORT_SIG_FLG_ASYNC
+ | ERTS_PORT_SIG_FLG_NOSUSPEND
+ | ERTS_PORT_SIG_FLG_FORCE))
+ == (ERTS_PORT_SIG_FLG_ASYNC
+ | ERTS_PORT_SIG_FLG_NOSUSPEND));
+
try_call = (force_immediate_call /* crash dumping */
|| !(sched_flags & (invalid_flags
| ERTS_PTS_FLGS_FORCE_SCHEDULE_OP)));
@@ -1995,6 +2005,15 @@ erts_port_output(Process *c_p,
return ERTS_PORT_OP_DONE;
case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
sched_flags = try_call_state.sched_flags;
+ if (async_nosuspend
+ && (sched_flags & (busy_flgs|ERTS_PTS_FLG_EXIT))) {
+ driver_free_binary(cbin);
+ if (evp != &ev)
+ erts_free(ERTS_ALC_T_TMP, evp);
+ return ((sched_flags & ERTS_PTS_FLG_EXIT)
+ ? ERTS_PORT_OP_DROPPED
+ : ERTS_PORT_OP_BUSY);
+ }
case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
/* Schedule outputv() call instead... */
break;
@@ -2142,6 +2161,13 @@ erts_port_output(Process *c_p,
return ERTS_PORT_OP_DONE;
case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
sched_flags = try_call_state.sched_flags;
+ if (async_nosuspend
+ && (sched_flags & (busy_flgs|ERTS_PTS_FLG_EXIT))) {
+ erts_free(ERTS_ALC_T_TMP, buf);
+ return ((sched_flags & ERTS_PTS_FLG_EXIT)
+ ? ERTS_PORT_OP_DROPPED
+ : ERTS_PORT_OP_BUSY);
+ }
case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
/* Schedule outputv() call instead... */
break;
@@ -2163,20 +2189,33 @@ erts_port_output(Process *c_p,
task_flags = ERTS_PT_FLG_WAIT_BUSY;
sigdp->flags |= flags;
+ ns_pthp = NULL;
if (flags & (ERTS_P2P_SIG_DATA_FLG_FORCE|ERTS_P2P_SIG_DATA_FLG_NOSUSPEND)) {
task_flags = 0;
if (flags & ERTS_P2P_SIG_DATA_FLG_FORCE)
sigdp->flags &= ~ERTS_P2P_SIG_DATA_FLG_NOSUSPEND;
+ else if (async_nosuspend) {
+ ErtsSchedulerData *esdp = (c_p
+ ? ERTS_PROC_GET_SCHDATA(c_p)
+ : erts_get_scheduler_data());
+ ASSERT(esdp);
+ ns_pthp = &esdp->nosuspend_port_task_handle;
+ sigdp->flags &= ~ERTS_P2P_SIG_DATA_FLG_NOSUSPEND;
+ }
else if (flags & ERTS_P2P_SIG_DATA_FLG_NOSUSPEND)
task_flags = ERTS_PT_FLG_NOSUSPEND;
}
+ ASSERT(ns_pthp || !async_nosuspend);
+ ASSERT(async_nosuspend || !ns_pthp);
+
res = erts_schedule_proc2port_signal(c_p,
prt,
c_p ? c_p->common.id : ERTS_INVALID_PID,
refp,
sigdp,
task_flags,
+ ns_pthp,
port_sig_callback);
if (res != ERTS_PORT_OP_SCHEDULED) {
@@ -2187,9 +2226,23 @@ erts_port_output(Process *c_p,
return res;
}
- if (!(sched_flags & ERTS_PTS_FLG_EXIT) && (sched_flags & busy_flgs))
- return ERTS_PORT_OP_BUSY_SCHEDULED;
-
+ if (!(flags & ERTS_PORT_SIG_FLG_FORCE)) {
+ sched_flags = erts_smp_atomic32_read_acqb(&prt->sched.flags);
+ if (!(sched_flags & ERTS_PTS_FLG_BUSY_PORT)) {
+ if (async_nosuspend)
+ erts_port_task_tmp_handle_detach(ns_pthp);
+ }
+ else {
+ if (!async_nosuspend)
+ return ERTS_PORT_OP_BUSY_SCHEDULED;
+ else {
+ if (erts_port_task_abort(ns_pthp) == 0)
+ return ERTS_PORT_OP_BUSY;
+ else
+ erts_port_task_tmp_handle_detach(ns_pthp);
+ }
+ }
+ }
return res;
bad_value:
@@ -2285,6 +2338,7 @@ erts_port_exit(Process *c_p,
ErlHeapFragment *bp = NULL;
ASSERT((flags & ~(ERTS_PORT_SIG_FLG_BANG_OP
+ | ERTS_PORT_SIG_FLG_ASYNC
| ERTS_PORT_SIG_FLG_BROKEN_LINK
| ERTS_PORT_SIG_FLG_FORCE_SCHED)) == 0);
@@ -2345,6 +2399,7 @@ erts_port_exit(Process *c_p,
refp,
sigdp,
0,
+ NULL,
port_sig_exit);
if (res == ERTS_PORT_OP_DROPPED) {
@@ -2460,7 +2515,8 @@ erts_port_connect(Process *c_p,
!refp,
am_connect);
- ASSERT((flags & ~ERTS_PORT_SIG_FLG_BANG_OP) == 0);
+ ASSERT((flags & ~(ERTS_PORT_SIG_FLG_BANG_OP
+ | ERTS_PORT_SIG_FLG_ASYNC)) == 0);
if (is_not_internal_pid(connect))
connect_id = NIL; /* Fail in op (for signal order) */
@@ -2499,6 +2555,7 @@ erts_port_connect(Process *c_p,
refp,
sigdp,
0,
+ NULL,
port_sig_connect);
}
@@ -2555,6 +2612,7 @@ erts_port_unlink(Process *c_p, Port *prt, Eterm from, Eterm *refp)
refp,
sigdp,
0,
+ NULL,
port_sig_unlink);
}
@@ -2644,6 +2702,7 @@ erts_port_link(Process *c_p, Port *prt, Eterm to, Eterm *refp)
refp,
sigdp,
0,
+ NULL,
port_sig_link);
}
@@ -3371,11 +3430,8 @@ terminate_port(Port *prt)
erts_free(ERTS_ALC_T_LINEBUF, (void *) prt->linebuf);
prt->linebuf = NULL;
}
- if (prt->bp != NULL) {
- free_message_buffer(prt->bp);
- prt->bp = NULL;
- prt->data = am_undefined;
- }
+
+ erts_cleanup_port_data(prt);
if (prt->psd)
erts_free(ERTS_ALC_T_PRTSD, prt->psd);
@@ -3625,6 +3681,10 @@ erts_port_command(Process *c_p,
ASSERT(port);
flags |= ERTS_PORT_SIG_FLG_BANG_OP;
+ if (!erts_port_synchronous_ops) {
+ flags |= ERTS_PORT_SIG_FLG_ASYNC;
+ refp = NULL;
+ }
if (is_tuple_arity(command, 2)) {
Eterm cntd;
@@ -3632,21 +3692,14 @@ erts_port_command(Process *c_p,
cntd = tp[1];
if (is_internal_pid(cntd)) {
if (tp[2] == am_close) {
- if (!erts_port_synchronous_ops)
- refp = NULL;
flags &= ~ERTS_PORT_SIG_FLG_NOSUSPEND;
return erts_port_exit(c_p, flags, port, cntd, am_normal, refp);
} else if (is_tuple_arity(tp[2], 2)) {
tp = tuple_val(tp[2]);
if (tp[1] == am_command) {
- if (!(flags & ERTS_PORT_SIG_FLG_NOSUSPEND)
- && !erts_port_synchronous_ops)
- refp = NULL;
return erts_port_output(c_p, flags, port, cntd, tp[2], refp);
}
else if (tp[1] == am_connect) {
- if (!erts_port_synchronous_ops)
- refp = NULL;
flags &= ~ERTS_PORT_SIG_FLG_NOSUSPEND;
return erts_port_connect(c_p, flags, port, cntd, tp[2], refp);
}
@@ -3655,8 +3708,6 @@ erts_port_command(Process *c_p,
}
/* badsig */
- if (!erts_port_synchronous_ops)
- refp = NULL;
flags &= ~ERTS_PORT_SIG_FLG_NOSUSPEND;
return bad_port_signal(c_p, flags, port, c_p->common.id, refp, am_command);
}
@@ -4053,6 +4104,7 @@ erts_port_control(Process* c_p,
retvalp,
sigdp,
0,
+ NULL,
port_sig_control);
if (res != ERTS_PORT_OP_SCHEDULED) {
cleanup_scheduled_control(binp, bufp);
@@ -4147,7 +4199,7 @@ port_sig_call(Port *prt,
ErlOffHeap *ohp;
Process *rp;
ErtsProcLocks rp_locks = 0;
- Uint hsz;
+ Sint hsz;
rp = erts_proc_lookup_raw(sigdp->caller);
if (!rp)
@@ -4264,7 +4316,7 @@ erts_port_call(Process* c_p,
switch (try_call_res) {
case ERTS_TRY_IMM_DRV_CALL_OK: {
Eterm *hp, *hp_end;
- Uint hsz;
+ Sint hsz;
unsigned ret_flags = 0U;
Eterm term;
@@ -4333,6 +4385,7 @@ erts_port_call(Process* c_p,
retvalp,
sigdp,
0,
+ NULL,
port_sig_call);
if (res != ERTS_PORT_OP_SCHEDULED) {
cleanup_scheduled_call(bufp);
@@ -4499,228 +4552,10 @@ erts_port_info(Process* c_p,
retvalp,
sigdp,
0,
+ NULL,
port_sig_info);
}
-static int
-port_sig_set_data(Port *prt,
- erts_aint32_t state,
- int op,
- ErtsProc2PortSigData *sigdp)
-{
- ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
-
- if (op == ERTS_PROC2PORT_SIG_EXEC) {
- if (prt->bp)
- free_message_buffer(prt->bp);
- prt->bp = sigdp->u.set_data.bp;
- prt->data = sigdp->u.set_data.data;
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_true);
- }
- else {
- if (sigdp->u.set_data.bp)
- free_message_buffer(sigdp->u.set_data.bp);
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
- }
- return ERTS_PORT_REDS_SET_DATA;
-}
-
-ErtsPortOpResult
-erts_port_set_data(Process* c_p,
- Port *prt,
- Eterm data,
- Eterm *refp)
-{
- ErtsPortOpResult res;
- Eterm set_data;
- ErlHeapFragment *bp;
- ErtsProc2PortSigData *sigdp;
- ErtsTryImmDrvCallResult try_call_res;
- ErtsTryImmDrvCallState try_call_state
- = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
- c_p,
- prt,
- ERTS_PORT_SFLGS_INVALID_LOOKUP,
- 0,
- !refp,
- am_set_data);
-
- if (is_immed(data)) {
- set_data = data;
- bp = NULL;
- }
- else {
- Eterm *hp;
- Uint sz = size_object(data);
- bp = new_message_buffer(sz);
- hp = bp->mem;
- set_data = copy_struct(data, sz, &hp, &bp->off_heap);
- }
-
- try_call_res = try_imm_drv_call(&try_call_state);
- switch (try_call_res) {
- case ERTS_TRY_IMM_DRV_CALL_OK:
- if (prt->bp)
- free_message_buffer(prt->bp);
- prt->bp = bp;
- prt->data = set_data;
- finalize_imm_drv_call(&try_call_state);
- BUMP_REDS(c_p, ERTS_PORT_REDS_SET_DATA);
- return ERTS_PORT_OP_DONE;
- case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
- return ERTS_PORT_OP_DROPPED;
- case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
- case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
- /* Schedule call instead... */
- break;
- }
-
- sigdp = erts_port_task_alloc_p2p_sig_data();
- sigdp->flags = ERTS_P2P_SIG_TYPE_SET_DATA;
- sigdp->u.set_data.data = set_data;
- sigdp->u.set_data.bp = bp;
-
- res = erts_schedule_proc2port_signal(c_p,
- prt,
- c_p->common.id,
- refp,
- sigdp,
- 0,
- port_sig_set_data);
- if (res != ERTS_PORT_OP_SCHEDULED && bp)
- free_message_buffer(bp);
- return res;
-}
-
-static int
-port_sig_get_data(Port *prt,
- erts_aint32_t state,
- int op,
- ErtsProc2PortSigData *sigdp)
-{
- ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
- if (op != ERTS_PROC2PORT_SIG_EXEC)
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
- else {
- Process *rp;
- ErtsProcLocks rp_locks = 0;
-
- rp = erts_proc_lookup_raw(sigdp->caller);
- if (rp) {
- Uint hsz;
- Eterm *hp, *hp_start;
- Eterm data, msg;
- ErlHeapFragment *bp;
- ErlOffHeap *ohp;
-
- hsz = ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE;
- hsz += 3;
- if (prt->bp)
- hsz += prt->bp->used_size;
-
- hp_start = hp = erts_alloc_message_heap(hsz,
- &bp,
- &ohp,
- rp,
- &rp_locks);
-
- if (is_immed(prt->data))
- data = prt->data;
- else
- data = copy_struct(prt->data,
- prt->bp->used_size,
- &hp,
- &bp->off_heap);
-
-
-
- msg = TUPLE2(hp, am_ok, data);
- hp += 3;
-
- queue_port_sched_op_reply(rp,
- &rp_locks,
- hp_start,
- hp,
- hsz,
- bp,
- sigdp->ref,
- msg);
- if (rp_locks)
- erts_smp_proc_unlock(rp, rp_locks);
- }
- }
- return ERTS_PORT_REDS_GET_DATA;
-}
-
-ErtsPortOpResult
-erts_port_get_data(Process* c_p,
- Port *prt,
- Eterm *retvalp)
-{
- ErtsProc2PortSigData *sigdp;
- ErtsTryImmDrvCallResult try_call_res;
- ErtsTryImmDrvCallState try_call_state
- = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
- c_p,
- prt,
- ERTS_PORT_SFLGS_INVALID_LOOKUP,
- 0,
- 0,
- am_get_data);
-
- try_call_res = try_imm_drv_call(&try_call_state);
- switch (try_call_res) {
- case ERTS_TRY_IMM_DRV_CALL_OK: {
- Eterm *hp;
- Eterm data;
- ErlHeapFragment *bp;
- Uint sz;
- if (is_immed(prt->data)) {
- bp = NULL;
- data = prt->data;
- }
- else {
- bp = new_message_buffer(prt->bp->used_size);
- data = copy_struct(prt->data,
- prt->bp->used_size,
- &hp,
- &bp->off_heap);
- }
- finalize_imm_drv_call(&try_call_state);
- if (is_immed(data))
- sz = 0;
- else
- sz = bp->used_size;
-
- hp = HAlloc(c_p, sz + 3);
- if (is_not_immed(data)) {
- data = copy_struct(data, bp->used_size, &hp, &MSO(c_p));
- free_message_buffer(bp);
- }
- *retvalp = TUPLE2(hp, am_ok, data);
- BUMP_REDS(c_p, ERTS_PORT_REDS_GET_DATA);
- return ERTS_PORT_OP_DONE;
- }
- case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
- return ERTS_PORT_OP_DROPPED;
- case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
- case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
- /* Schedule call instead... */
- break;
- }
-
- sigdp = erts_port_task_alloc_p2p_sig_data();
- sigdp->flags = ERTS_P2P_SIG_TYPE_GET_DATA;
-
- return erts_schedule_proc2port_signal(c_p,
- prt,
- c_p->common.id,
- retvalp,
- sigdp,
- 0,
- port_sig_get_data);
-}
-
typedef struct {
int to;
void *arg;
@@ -5941,10 +5776,6 @@ int driver_outputv(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
return driver_output2(ix, hbuf, hlen, NULL, 0);
size = vec->size - skip; /* Size of remaining bytes in vector */
- ASSERT(hlen >= 0); /* debug only */
- if (hlen < 0)
- hlen = 0;
-
prt = erts_drvport2port_state(ix, &state);
if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 2451f41a82..301ce2d0e2 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -678,8 +678,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_LOPT_UDP_READ_PACKETS 33 /* Number of packets to read */
#define INET_OPT_RAW 34 /* Raw socket options */
#define INET_LOPT_TCP_SEND_TIMEOUT_CLOSE 35 /* auto-close on send timeout or not */
-#define INET_LOPT_TCP_MSGQ_HIWTRMRK 36 /* set local high watermark */
-#define INET_LOPT_TCP_MSGQ_LOWTRMRK 37 /* set local low watermark */
+#define INET_LOPT_MSGQ_HIWTRMRK 36 /* set local msgq high watermark */
+#define INET_LOPT_MSGQ_LOWTRMRK 37 /* set local msgq low watermark */
/* SCTP options: a separate range, from 100: */
#define SCTP_OPT_RTOINFO 100
#define SCTP_OPT_ASSOCINFO 101
@@ -5476,27 +5476,25 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
}
continue;
- case INET_LOPT_TCP_MSGQ_HIWTRMRK:
- if (desc->stype == SOCK_STREAM) {
- ErlDrvSizeT high;
- if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
- || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
- return -1;
- high = (ErlDrvSizeT) ival;
- erl_drv_busy_msgq_limits(desc->port, NULL, &high);
- }
+ case INET_LOPT_MSGQ_HIWTRMRK: {
+ ErlDrvSizeT high;
+ if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
+ || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
+ return -1;
+ high = (ErlDrvSizeT) ival;
+ erl_drv_busy_msgq_limits(desc->port, NULL, &high);
continue;
+ }
- case INET_LOPT_TCP_MSGQ_LOWTRMRK:
- if (desc->stype == SOCK_STREAM) {
- ErlDrvSizeT low;
- if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
- || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
- return -1;
- low = (ErlDrvSizeT) ival;
- erl_drv_busy_msgq_limits(desc->port, &low, NULL);
- }
+ case INET_LOPT_MSGQ_LOWTRMRK: {
+ ErlDrvSizeT low;
+ if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
+ || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
+ return -1;
+ low = (ErlDrvSizeT) ival;
+ erl_drv_busy_msgq_limits(desc->port, &low, NULL);
continue;
+ }
case INET_LOPT_TCP_SEND_TIMEOUT:
if (desc->stype == SOCK_STREAM) {
@@ -6398,31 +6396,23 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
}
continue;
- case INET_LOPT_TCP_MSGQ_HIWTRMRK:
- if (desc->stype == SOCK_STREAM) {
- ErlDrvSizeT high = ERL_DRV_BUSY_MSGQ_READ_ONLY;
- *ptr++ = opt;
- erl_drv_busy_msgq_limits(desc->port, NULL, &high);
- ival = high > INT_MAX ? INT_MAX : (int) high;
- put_int32(ival, ptr);
- }
- else {
- TRUNCATE_TO(0,ptr);
- }
+ case INET_LOPT_MSGQ_HIWTRMRK: {
+ ErlDrvSizeT high = ERL_DRV_BUSY_MSGQ_READ_ONLY;
+ *ptr++ = opt;
+ erl_drv_busy_msgq_limits(desc->port, NULL, &high);
+ ival = high > INT_MAX ? INT_MAX : (int) high;
+ put_int32(ival, ptr);
continue;
+ }
- case INET_LOPT_TCP_MSGQ_LOWTRMRK:
- if (desc->stype == SOCK_STREAM) {
- ErlDrvSizeT low = ERL_DRV_BUSY_MSGQ_READ_ONLY;
- *ptr++ = opt;
- erl_drv_busy_msgq_limits(desc->port, &low, NULL);
- ival = low > INT_MAX ? INT_MAX : (int) low;
- put_int32(ival, ptr);
- }
- else {
- TRUNCATE_TO(0,ptr);
- }
+ case INET_LOPT_MSGQ_LOWTRMRK: {
+ ErlDrvSizeT low = ERL_DRV_BUSY_MSGQ_READ_ONLY;
+ *ptr++ = opt;
+ erl_drv_busy_msgq_limits(desc->port, &low, NULL);
+ ival = low > INT_MAX ? INT_MAX : (int) low;
+ put_int32(ival, ptr);
continue;
+ }
case INET_LOPT_TCP_SEND_TIMEOUT:
if (desc->stype == SOCK_STREAM) {
@@ -7471,6 +7461,20 @@ static void inet_stop(inet_descriptor* desc)
FREE(desc);
}
+static void set_default_msgq_limits(ErlDrvPort port)
+{
+ ErlDrvSizeT q_high = INET_HIGH_MSGQ_WATERMARK;
+ ErlDrvSizeT q_low = INET_LOW_MSGQ_WATERMARK;
+ if (q_low < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ q_low = ERL_DRV_BUSY_MSGQ_LIM_MIN;
+ else if (q_low > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ q_low = ERL_DRV_BUSY_MSGQ_LIM_MAX;
+ if (q_high < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ q_high = ERL_DRV_BUSY_MSGQ_LIM_MIN;
+ else if (q_high > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ q_high = ERL_DRV_BUSY_MSGQ_LIM_MAX;
+ erl_drv_busy_msgq_limits(port, &q_low, &q_high);
+}
/* Allocate descriptor */
static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
@@ -8091,9 +8095,8 @@ static int tcp_inet_init(void)
/* initialize the TCP descriptor */
-static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
+static ErlDrvData prep_tcp_inet_start(ErlDrvPort port, char* args)
{
- ErlDrvSizeT q_low, q_high;
tcp_descriptor* desc;
DEBUGF(("tcp_inet_start(%ld) {\r\n", (long)port));
@@ -8103,17 +8106,6 @@ static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
return ERL_DRV_ERROR_ERRNO;
desc->high = INET_HIGH_WATERMARK;
desc->low = INET_LOW_WATERMARK;
- q_high = INET_HIGH_MSGQ_WATERMARK;
- q_low = INET_LOW_MSGQ_WATERMARK;
- if (q_low < ERL_DRV_BUSY_MSGQ_LIM_MIN)
- q_low = ERL_DRV_BUSY_MSGQ_LIM_MIN;
- else if (q_low > ERL_DRV_BUSY_MSGQ_LIM_MAX)
- q_low = ERL_DRV_BUSY_MSGQ_LIM_MAX;
- if (q_high < ERL_DRV_BUSY_MSGQ_LIM_MIN)
- q_high = ERL_DRV_BUSY_MSGQ_LIM_MIN;
- else if (q_high > ERL_DRV_BUSY_MSGQ_LIM_MAX)
- q_high = ERL_DRV_BUSY_MSGQ_LIM_MAX;
- erl_drv_busy_msgq_limits(port, &q_low, &q_high);
desc->send_timeout = INET_INFINITY;
desc->send_timeout_close = 0;
desc->busy_on_send = 0;
@@ -8130,6 +8122,12 @@ static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
return (ErlDrvData) desc;
}
+static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
+{
+ ErlDrvData data = prep_tcp_inet_start(port, args);
+ set_default_msgq_limits(port);
+ return data;
+}
/* Copy a descriptor, by creating a new port with same settings
* as the descriptor desc.
* return NULL on error (SYSTEM_LIMIT no ports avail)
@@ -8141,7 +8139,7 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
ErlDrvPort port = desc->inet.port;
tcp_descriptor* copy_desc;
- copy_desc = (tcp_descriptor*) tcp_inet_start(port, NULL);
+ copy_desc = (tcp_descriptor*) prep_tcp_inet_start(port, NULL);
/* Setup event if needed */
if ((copy_desc->inet.s = s) != INVALID_SOCKET) {
@@ -9864,12 +9862,15 @@ static int should_use_so_bsdcompat(void)
* as the descriptor desc.
* return NULL on error (ENFILE no ports avail)
*/
+static ErlDrvData packet_inet_start(ErlDrvPort port, char* args, int protocol);
+
static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err)
{
+ ErlDrvSizeT q_low, q_high;
ErlDrvPort port = desc->inet.port;
udp_descriptor* copy_desc;
- copy_desc = (udp_descriptor*) sctp_inet_start(port, NULL);
+ copy_desc = (udp_descriptor*) packet_inet_start(port, NULL, IPPROTO_SCTP);
/* Setup event if needed */
if ((copy_desc->inet.s = s) != INVALID_SOCKET) {
@@ -9900,9 +9901,17 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err)
FREE(copy_desc);
return NULL;
}
+
+ /* Read busy msgq limits of parent */
+ q_low = q_high = ERL_DRV_BUSY_MSGQ_READ_ONLY;
+ erl_drv_busy_msgq_limits(desc->inet.port, &q_low, &q_high);
+ /* Write same busy msgq limits to child */
+ erl_drv_busy_msgq_limits(port, &q_low, &q_high);
+
copy_desc->inet.port = port;
copy_desc->inet.dport = driver_mk_port(port);
*err = 0;
+
return copy_desc;
}
#endif
@@ -9935,13 +9944,17 @@ static ErlDrvData packet_inet_start(ErlDrvPort port, char* args, int protocol)
static ErlDrvData udp_inet_start(ErlDrvPort port, char *args)
{
- return packet_inet_start(port, args, IPPROTO_UDP);
+ ErlDrvData data = packet_inet_start(port, args, IPPROTO_UDP);
+ set_default_msgq_limits(port);
+ return data;
}
#ifdef HAVE_SCTP
static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args)
{
- return packet_inet_start(port, args, IPPROTO_SCTP);
+ ErlDrvData data = packet_inet_start(port, args, IPPROTO_SCTP);
+ set_default_msgq_limits(port);
+ return data;
}
#endif
diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c
index 8912d148a5..1e436830e7 100644
--- a/erts/emulator/drivers/unix/ttsl_drv.c
+++ b/erts/emulator/drivers/unix/ttsl_drv.c
@@ -42,6 +42,9 @@ static ErlDrvData ttysl_start(ErlDrvPort, char*);
#include <locale.h>
#include <unistd.h>
#include <termios.h>
+#ifdef HAVE_WCWIDTH
+#include <wchar.h>
+#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
@@ -95,6 +98,9 @@ static int lpos; /* The current "cursor position" in the line buf
*/
#define CONTROL_TAG 0x10000000U /* Control character, value in first position */
#define ESCAPED_TAG 0x01000000U /* Escaped character, value in first position */
+#ifdef HAVE_WCWIDTH
+#define WIDE_TAG 0x02000000U /* Wide character, value in first position */
+#endif
#define TAG_MASK 0xFF000000U
#define MAXSIZE (1 << 16)
@@ -597,12 +603,20 @@ static int check_buf_size(byte *s, int n)
}
if (utf8_mode) { /* That is, terminal is UTF8 compliant */
if (ch >= 128 || isprint(ch)) {
- DEBUGLOG(("Printable(UTF-8:%d):%d",(pos - opos),ch));
- size++; /* Buffer contains wide characters... */
+#ifdef HAVE_WCWIDTH
+ int width;
+#endif
+ DEBUGLOG(("Printable(UTF-8:%d):%d",pos,ch));
+ size++;
+#ifdef HAVE_WCWIDTH
+ if ((width = wcwidth(ch)) > 1) {
+ size += width - 1;
+ }
+#endif
} else if (ch == '\t') {
size += 8;
} else {
- DEBUGLOG(("Magic(UTF-8:%d):%d",(pos - opos),ch));
+ DEBUGLOG(("Magic(UTF-8:%d):%d",pos,ch));
size += 2;
}
} else {
@@ -823,7 +837,7 @@ static int del_chars(int n)
r = llen - lpos - l; /* Characters after deleted */
/* Fix up buffer and buffer pointers. */
if (r > 0)
- memcpy(lbuf + lpos, lbuf + pos, r * sizeof(Uint32));
+ memmove(lbuf + lpos, lbuf + pos, r * sizeof(Uint32));
llen -= l;
/* Write out characters after, blank the tail and jump back to lpos. */
write_buf(lbuf + lpos, r);
@@ -842,7 +856,7 @@ static int del_chars(int n)
move_cursor(lpos, lpos-l); /* Move back */
/* Fix up buffer and buffer pointers. */
if (r > 0)
- memcpy(lbuf + pos, lbuf + lpos, r * sizeof(Uint32));
+ memmove(lbuf + pos, lbuf + lpos, r * sizeof(Uint32));
lpos -= l;
llen -= l;
/* Write out characters after, blank the tail and jump back to lpos. */
@@ -868,12 +882,22 @@ static int step_over_chars(int n)
end = lbuf + llen;
c = lbuf + lpos;
for ( ; n > 0 && c < end; --n) {
+#ifdef HAVE_WCWIDTH
+ while (*c & WIDE_TAG) {
+ c++;
+ }
+#endif
c++;
while (c < end && (*c & TAG_MASK) && ((*c & ~TAG_MASK) == 0))
c++;
}
for ( ; n < 0 && c > beg; n++) {
--c;
+#ifdef HAVE_WCWIDTH
+ while (c > beg + 1 && (c[-1] & WIDE_TAG)) {
+ --c;
+ }
+#endif
while (c > beg && (*c & TAG_MASK) && ((*c & ~TAG_MASK) == 0))
--c;
}
@@ -899,6 +923,15 @@ static int insert_buf(byte *s, int n)
++pos;
}
if ((utf8_mode && (ch >= 128 || isprint(ch))) || (ch <= 255 && isprint(ch))) {
+#ifdef HAVE_WCWIDTH
+ int width;
+ if ((width = wcwidth(ch)) > 1) {
+ while (--width) {
+ DEBUGLOG(("insert_buf: Wide(UTF-8):%d,%d",width,ch));
+ lbuf[lpos++] = (WIDE_TAG | ((Uint32) ch));
+ }
+ }
+#endif
DEBUGLOG(("insert_buf: Printable(UTF-8):%d",ch));
lbuf[lpos++] = (Uint32) ch;
} else if (ch >= 128) { /* not utf8 mode */
@@ -1006,6 +1039,10 @@ static int write_buf(Uint32 *s, int n)
if (octbuff != octtmp) {
driver_free(octbuff);
}
+#ifdef HAVE_WCWIDTH
+ } else if (*s & WIDE_TAG) {
+ --n; s++;
+#endif
} else {
DEBUGLOG(("Very unexpected character %d",(int) *s));
++n;
diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c
index 1a74d21e99..8b5e3eeefd 100644
--- a/erts/emulator/drivers/win32/ttsl_drv.c
+++ b/erts/emulator/drivers/win32/ttsl_drv.c
@@ -414,12 +414,12 @@ static int check_buf_size(byte *s, int n)
}
if (utf8_mode) { /* That is, terminal is UTF8 compliant */
if (ch >= 128 || isprint(ch)) {
- DEBUGLOG(("Printable(UTF-8:%d):%d",(pos - opos),ch));
+ DEBUGLOG(("Printable(UTF-8:%d):%d",pos,ch));
size++; /* Buffer contains wide characters... */
} else if (ch == '\t') {
size += 8;
} else {
- DEBUGLOG(("Magic(UTF-8:%d):%d",(pos - opos),ch));
+ DEBUGLOG(("Magic(UTF-8:%d):%d",pos,ch));
size += 2;
}
} else {
diff --git a/erts/emulator/hipe/hipe_x86_signal.c b/erts/emulator/hipe/hipe_x86_signal.c
index 64c0e0da3e..19fc448742 100644
--- a/erts/emulator/hipe/hipe_x86_signal.c
+++ b/erts/emulator/hipe/hipe_x86_signal.c
@@ -183,6 +183,7 @@ static void do_init(void)
#include <dlfcn.h>
static int (*__next_sigaction)(int, const struct sigaction*, struct sigaction*);
#define init_done() (__next_sigaction != 0)
+extern int _sigaction(int, const struct sigaction*, struct sigaction*);
#define __SIGACTION _sigaction
static void do_init(void)
{
diff --git a/erts/emulator/internal_doc/dec.erl b/erts/emulator/internal_doc/dec.erl
index 0315f2a52d..255018abe0 100644
--- a/erts/emulator/internal_doc/dec.erl
+++ b/erts/emulator/internal_doc/dec.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -25,10 +26,10 @@
%% {RevList,Translation}
%% Where 'RevList' is a reversed list of the denormalized repressentation of
%% the character 'Translation'. An example would be the swedish character
-%% '�', which would be represented in the file as:
+%% 'ö', which would be represented in the file as:
%% {[776,111],246}, as the denormalized representation of codepoint 246
%% is [111,776] (i.e an 'o' followed by the "double dot accent character 776),
-%% while '�' instead is represented as {[776,97],228}, as the denormalized
+%% while 'ä' instead is represented as {[776,97],228}, as the denormalized
%% form would be [97,776] (same accent but an 'a' instead).
%% The datafile is generated from the table on Apple's developer connection
%% http://developer.apple.com/library/mac/#technotes/tn/tn1150table.html
diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c
index b6e2c9382b..2748edba02 100644
--- a/erts/emulator/sys/common/erl_mseg.c
+++ b/erts/emulator/sys/common/erl_mseg.c
@@ -1749,45 +1749,42 @@ erts_mseg_late_init(void)
#endif /* #if HAVE_ERTS_MSEG */
-unsigned long
-erts_mseg_test(unsigned long op,
- unsigned long a1,
- unsigned long a2,
- unsigned long a3)
+UWord
+erts_mseg_test(UWord op, UWord a1, UWord a2, UWord a3)
{
switch (op) {
#if HAVE_ERTS_MSEG
case 0x400: /* Have erts_mseg */
- return (unsigned long) 1;
+ return (UWord) 1;
case 0x401:
- return (unsigned long) erts_mseg_alloc(ERTS_ALC_A_INVALID, (Uint *) a1, (Uint) 0);
+ return (UWord) erts_mseg_alloc(ERTS_ALC_A_INVALID, (Uint *) a1, (Uint) 0);
case 0x402:
erts_mseg_dealloc(ERTS_ALC_A_INVALID, (void *) a1, (Uint) a2, (Uint) 0);
- return (unsigned long) 0;
+ return (UWord) 0;
case 0x403:
- return (unsigned long) erts_mseg_realloc(ERTS_ALC_A_INVALID,
+ return (UWord) erts_mseg_realloc(ERTS_ALC_A_INVALID,
(void *) a1,
(Uint) a2,
(Uint *) a3,
(Uint) 0);
case 0x404:
erts_mseg_clear_cache();
- return (unsigned long) 0;
+ return (UWord) 0;
case 0x405:
- return (unsigned long) erts_mseg_no(&erts_mseg_default_opt);
+ return (UWord) erts_mseg_no(&erts_mseg_default_opt);
case 0x406: {
ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_IX(0);
- unsigned long res;
+ UWord res;
ERTS_MSEG_LOCK(ma);
- res = (unsigned long) tot_cache_size(ma);
+ res = (UWord) tot_cache_size(ma);
ERTS_MSEG_UNLOCK(ma);
return res;
}
#else /* #if HAVE_ERTS_MSEG */
case 0x400: /* Have erts_mseg */
- return (unsigned long) 0;
+ return (UWord) 0;
#endif /* #if HAVE_ERTS_MSEG */
- default: ASSERT(0); return ~((unsigned long) 0);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/sys/common/erl_mseg.h b/erts/emulator/sys/common/erl_mseg.h
index 3cab9e18da..a4f250ceab 100644
--- a/erts/emulator/sys/common/erl_mseg.h
+++ b/erts/emulator/sys/common/erl_mseg.h
@@ -109,9 +109,6 @@ Eterm erts_mseg_info(int, int *, void*, int, Uint **, Uint *);
#endif /* #if HAVE_ERTS_MSEG */
-unsigned long erts_mseg_test(unsigned long,
- unsigned long,
- unsigned long,
- unsigned long);
+UWord erts_mseg_test(UWord, UWord, UWord, UWord);
#endif /* #ifndef ERL_MSEG_H_ */
diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c
index 787f8d6728..689be98969 100644
--- a/erts/emulator/sys/unix/sys_float.c
+++ b/erts/emulator/sys/unix/sys_float.c
@@ -832,6 +832,8 @@ sys_chars_to_double(char* buf, double* fp)
return 0;
}
+#ifdef USE_MATHERR
+
int
matherr(struct exception *exc)
{
@@ -842,3 +844,5 @@ matherr(struct exception *exc)
#endif
return 1;
}
+
+#endif
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index e0422de026..922967c698 100755
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -399,11 +399,12 @@ int* pBuild; /* Pointer to build number. */
* Definitions for driver flags.
*/
-#define DF_OVR_READY 1 /* Overlapped result is ready. */
-#define DF_EXIT_THREAD 2 /* The thread should exit. */
-#define DF_XLAT_CR 4 /* The thread should translate CRs. */
-#define DF_DROP_IF_INVH 8 /* Drop packages instead of crash if
+#define DF_OVR_READY 1 /* Overlapped result is ready. */
+#define DF_EXIT_THREAD 2 /* The thread should exit. */
+#define DF_XLAT_CR 4 /* The thread should translate CRs. */
+#define DF_DROP_IF_INVH 8 /* Drop packages instead of crash if
invalid handle (stderr) */
+#define DF_THREAD_FLUSHED 16 /* The thread should exit. */
#define OV_BUFFER_PTR(dp) ((LPVOID) ((dp)->ov.Internal))
#define OV_NUM_TO_READ(dp) ((dp)->ov.InternalHigh)
@@ -2141,8 +2142,9 @@ threaded_writer(LPVOID param)
for (;;) {
handle = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
- if (aio->flags & DF_EXIT_THREAD)
+ if (aio->flags & DF_EXIT_THREAD) {
break;
+ }
buf = OV_BUFFER_PTR(aio);
numToWrite = OV_NUM_TO_READ(aio);
@@ -2150,6 +2152,7 @@ threaded_writer(LPVOID param)
if (handle == (WAIT_OBJECT_0 + 1) && numToWrite == 0) {
SetEvent(aio->flushReplyEvent);
+ aio->flags |= DF_THREAD_FLUSHED;
continue;
}
@@ -2197,6 +2200,7 @@ threaded_writer(LPVOID param)
if (aio->flags & DF_EXIT_THREAD)
break;
}
+ aio->flags |= DF_THREAD_FLUSHED;
CloseHandle(aio->fd);
aio->fd = INVALID_HANDLE_VALUE;
unrefer_driver_data(aio->dp);
@@ -2340,9 +2344,11 @@ static void fd_stop(ErlDrvData data)
(void) driver_select(dp->port_num,
(ErlDrvEvent)dp->out.ov.hEvent,
ERL_DRV_WRITE, 0);
- ASSERT(dp->out.flushEvent);
- SetEvent(dp->out.flushEvent);
- WaitForSingleObject(dp->out.flushReplyEvent, INFINITE);
+ do {
+ ASSERT(dp->out.flushEvent);
+ SetEvent(dp->out.flushEvent);
+ } while (WaitForSingleObject(dp->out.flushReplyEvent, 10) == WAIT_TIMEOUT
+ || !(dp->out.flags & DF_THREAD_FLUSHED));
}
}
@@ -2433,12 +2439,12 @@ threaded_exiter(LPVOID param)
*/
i = 0;
if (dp->out.thread != (HANDLE) -1) {
- dp->out.flags = DF_EXIT_THREAD;
+ dp->out.flags |= DF_EXIT_THREAD;
SetEvent(dp->out.ioAllowed);
handles[i++] = dp->out.thread;
}
if (dp->in.thread != (HANDLE) -1) {
- dp->in.flags = DF_EXIT_THREAD;
+ dp->in.flags |= DF_EXIT_THREAD;
SetEvent(dp->in.ioAllowed);
handles[i++] = dp->in.thread;
}
diff --git a/erts/emulator/sys/win32/sys_float.c b/erts/emulator/sys/win32/sys_float.c
index fb1ffc3089..0e19746cf5 100644
--- a/erts/emulator/sys/win32/sys_float.c
+++ b/erts/emulator/sys/win32/sys_float.c
@@ -52,7 +52,7 @@ void erts_thread_disable_fpe(void)
int
sys_chars_to_double(char *buf, double *fp)
{
- char *s = buf, *t, *dp;
+ unsigned char *s = buf, *t, *dp;
/* Robert says that something like this is what he really wanted:
* (The [.,] radix test is NOT what Robert wanted - it was added later)
@@ -120,7 +120,7 @@ sys_chars_to_double(char *buf, double *fp)
int
sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t decimals)
{
- char *s = buffer;
+ unsigned char *s = buffer;
if (erts_snprintf(buffer, buffer_size, "%.*e", decimals, fp) >= buffer_size)
return -1;
@@ -133,6 +133,8 @@ sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t deci
return s-buffer; /* i.e strlen(buffer) */
}
+#ifdef USE_MATHERR
+
int
matherr(struct _exception *exc)
{
@@ -141,6 +143,8 @@ matherr(struct _exception *exc)
return 1;
}
+#endif
+
static void
fpe_exception(int sig)
{
diff --git a/erts/emulator/test/busy_port_SUITE.erl b/erts/emulator/test/busy_port_SUITE.erl
index 2c63296b83..4b4af0babe 100644
--- a/erts/emulator/test/busy_port_SUITE.erl
+++ b/erts/emulator/test/busy_port_SUITE.erl
@@ -170,6 +170,7 @@ send_3(Config) when is_list(Config) ->
?line {Owner,Slave} = get_slave(),
?line ok = erlang:send(Slave, {Owner,{command,"set busy"}},
[nosuspend]),
+ receive after 100 -> ok end, % ensure command reached port
?line nosuspend = erlang:send(Slave, {Owner,{command,"busy"}},
[nosuspend]),
?line unlock_slave(),
@@ -563,6 +564,7 @@ scheduling_delay_busy_nosuspend(Config) ->
{2,{call,[{var,1},open_port]}},
{0,{cast,[{var,1},{command,1,100}]}},
{0,{cast,[{var,1},{busy,2}]}},
+ {0,{timer,sleep,[200]}}, % ensure reached port
{10,{call,[{var,1},{command,3,[nosuspend]}]}},
{0,{timer,sleep,[200]}},
{0,{erlang,port_command,[{var,2},<<$N>>,[force]]}},
diff --git a/erts/emulator/test/code_parallel_load_SUITE.erl b/erts/emulator/test/code_parallel_load_SUITE.erl
index aa9e4c96c6..d2c80c1ca0 100644
--- a/erts/emulator/test/code_parallel_load_SUITE.erl
+++ b/erts/emulator/test/code_parallel_load_SUITE.erl
@@ -16,7 +16,6 @@
%%
%% %CopyrightEnd%
%%
-%% Author: Björn-Egil Dahlberg
-module(code_parallel_load_SUITE).
-export([
diff --git a/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c b/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c
index 95a6ae9bdf..500725a7cd 100644
--- a/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c
@@ -58,7 +58,7 @@ void *
test_thread(void *vsize)
{
int i;
- int size = (int) (long) vsize;
+ int size = (int) (ErlDrvSInt) vsize;
void *mem;
mem = driver_alloc(size);
if (mem)
@@ -88,7 +88,7 @@ ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf,
res = erl_drv_thread_create("test_thread",
&tid,
test_thread,
- (void *) (long) size,
+ (void *) (ErlDrvSInt) size,
NULL);
if (res == 0) {
res = erl_drv_thread_join(tid, NULL);
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index c8f286f629..0c4a9f7e5c 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -40,7 +40,7 @@ typedef struct
int ref_cnt;
CallInfo* call_history;
NifModPrivData* nif_mod;
- union { ErlNifResourceType* t; long l; } rt_arr[2];
+ union { ErlNifResourceType* t; void* vp; } rt_arr[2];
} PrivData;
/*
@@ -93,6 +93,23 @@ struct binary_resource {
unsigned size;
};
+static int get_pointer(ErlNifEnv* env, ERL_NIF_TERM term, void** pp)
+{
+ ErlNifUInt64 i64;
+ int r = enif_get_uint64(env, term, &i64);
+ if (r) {
+ *pp = (void*)i64;
+ }
+ return r;
+}
+
+static ERL_NIF_TERM make_pointer(ErlNifEnv* env, void* p)
+{
+ ErlNifUInt64 i64 = (ErlNifUInt64) p;
+ return enif_make_uint64(env, i64);
+}
+
+
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
PrivData* data = enif_alloc(sizeof(PrivData));
@@ -224,15 +241,15 @@ static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_priv_data(env);
- unsigned long ptr_as_ulong;
+ void* ptr;
- if (!enif_get_ulong(env,argv[0],&ptr_as_ulong)) {
+ if (!get_pointer(env,argv[0],&ptr)) {
return enif_make_badarg(env);
}
if (data->nif_mod != NULL) {
NifModPrivData_release(data->nif_mod);
}
- data->nif_mod = (NifModPrivData*) ptr_as_ulong;
+ data->nif_mod = (NifModPrivData*) ptr;
return enif_make_int(env,++(data->nif_mod->ref_cnt));
}
@@ -696,7 +713,7 @@ static ERL_NIF_TERM last_resource_dtor_call(ErlNifEnv* env, int argc, const ERL_
memcpy(enif_make_new_binary(env, resource_dtor_last_sz, &bin),
resource_dtor_last_data, resource_dtor_last_sz);
ret = enif_make_tuple3(env,
- enif_make_long(env, (long)resource_dtor_last),
+ make_pointer(env, resource_dtor_last),
bin,
enif_make_int(env, resource_dtor_cnt));
}
@@ -717,40 +734,40 @@ static ERL_NIF_TERM get_resource_type(ErlNifEnv* env, int argc, const ERL_NIF_TE
if (!enif_get_int(env, argv[0], &ix) || ix >= 2) {
return enif_make_badarg(env);
}
- return enif_make_long(env, data->rt_arr[ix].l);
+ return make_pointer(env, data->rt_arr[ix].vp);
}
static ERL_NIF_TERM alloc_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
- union { ErlNifResourceType* t; long l; } type;
- union { void* p; long l;} data;
- if (!enif_get_long(env, argv[0], &type.l)
+ union { ErlNifResourceType* t; void* vp; } type;
+ void* data;
+ if (!get_pointer(env, argv[0], &type.vp)
|| !enif_inspect_binary(env, argv[1], &data_bin)
- || (data.p = enif_alloc_resource(type.t, data_bin.size))==NULL) {
+ || (data = enif_alloc_resource(type.t, data_bin.size))==NULL) {
return enif_make_badarg(env);
}
- memcpy(data.p, data_bin.data, data_bin.size);
- return enif_make_long(env, data.l);
+ memcpy(data, data_bin.data, data_bin.size);
+ return make_pointer(env, data);
}
static ERL_NIF_TERM make_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- union { void* p; long l; } data;
- if (!enif_get_long(env, argv[0], &data.l)) {
+ void* data;
+ if (!get_pointer(env, argv[0], &data)) {
return enif_make_badarg(env);
}
- return enif_make_resource(env, data.p);
+ return enif_make_resource(env, data);
}
static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
- union { ErlNifResourceType* t; long l; } type;
+ union { ErlNifResourceType* t; void* vp; } type;
void* data;
ERL_NIF_TERM ret;
- if (!enif_get_long(env, argv[0], &type.l)
+ if (!get_pointer(env, argv[0], &type.vp)
|| !enif_inspect_binary(env, argv[1], &data_bin)
|| (data = enif_alloc_resource(type.t, data_bin.size))==NULL) {
@@ -765,7 +782,7 @@ static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TE
static ERL_NIF_TERM make_new_resource_binary(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
- union { struct binary_resource* p; void* vp; long l; } br;
+ union { struct binary_resource* p; void* vp; } br;
void* buf;
ERL_NIF_TERM ret;
if (!enif_inspect_binary(env, argv[0], &data_bin)
@@ -781,7 +798,7 @@ static ERL_NIF_TERM make_new_resource_binary(ErlNifEnv* env, int argc, const ERL
memcpy(br.p->data, data_bin.data, data_bin.size);
ret = enif_make_resource_binary(env, br.vp, br.p->data, br.p->size);
enif_release_resource(br.p);
- return enif_make_tuple2(env, enif_make_long(env,br.l), ret);
+ return enif_make_tuple2(env, make_pointer(env,br.vp), ret);
}
static void binary_resource_dtor(ErlNifEnv* env, void* obj)
@@ -796,33 +813,33 @@ static void binary_resource_dtor(ErlNifEnv* env, void* obj)
static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
- union { ErlNifResourceType* t; long l; } type;
- union { void* p; long l; } data;
+ union { ErlNifResourceType* t; void* vp; } type;
+ void* data;
type.t = NULL;
if (enif_is_identical(argv[0], atom_binary_resource_type)) {
type.t = binary_resource_type;
}
else {
- enif_get_long(env, argv[0], &type.l);
+ get_pointer(env, argv[0], &type.vp);
}
if (type.t == NULL
- || !enif_get_resource(env, argv[1], type.t, &data.p)) {
+ || !enif_get_resource(env, argv[1], type.t, &data)) {
return enif_make_badarg(env);
}
- enif_alloc_binary(enif_sizeof_resource(data.p), &data_bin);
- memcpy(data_bin.data, data.p, data_bin.size);
- return enif_make_tuple2(env, enif_make_long(env,data.l),
+ enif_alloc_binary(enif_sizeof_resource(data), &data_bin);
+ memcpy(data_bin.data, data, data_bin.size);
+ return enif_make_tuple2(env, make_pointer(env,data),
enif_make_binary(env, &data_bin));
}
static ERL_NIF_TERM release_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- union { void* p; long l; } data;
- if (!enif_get_long(env, argv[0], &data.l)) {
+ void* data;
+ if (!get_pointer(env, argv[0], &data)) {
return enif_make_badarg(env);
}
- enif_release_resource(data.p);
+ enif_release_resource(data);
return enif_make_atom(env,"ok");
}
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index cc7d77fd9a..f99059cb72 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -171,6 +171,11 @@ while [ $# -gt 0 ]; do
cargs="$cargs -debug"
TYPE=.debug
;;
+ "-frmptr")
+ shift
+ cargs="$cargs -frmptr"
+ TYPE=.frmptr
+ ;;
"-gdb")
shift
GDB=gdb
diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in
index 0fc3ac6efc..4f0a5e5202 100644
--- a/erts/lib_src/Makefile.in
+++ b/erts/lib_src/Makefile.in
@@ -86,6 +86,12 @@ CFLAGS += -DERTS_ENABLE_LOCK_COUNT
OMIT_FP=true
PRE_LD=
else
+ifeq ($(TYPE),frmptr)
+TYPE_SUFFIX = .frmptr
+CFLAGS += -DERTS_FRMPTR
+OMIT_OMIT_FP=yes
+PRE_LD=
+else
override TYPE=opt
OMIT_FP=true
TYPE_SUFFIX=
@@ -98,6 +104,7 @@ endif
endif
endif
endif
+endif
OPSYS=@OPSYS@
sol2CFLAGS=
@@ -110,6 +117,7 @@ ultrasparcCFLAGS=-Wa,-xarch=v8plusa
ARCHCFLAGS=$($(ARCH)CFLAGS)
ifeq ($(OMIT_OMIT_FP),yes)
+CFLAGS += -fno-omit-frame-pointer
OMIT_FP=false
endif
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 29fb8aaebf..308cb99be5 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index c907ead38a..1b47509a53 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 7b9da42e4f..a0a4314128 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index fefe0f21e0..7106c0a4fb 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -2086,7 +2086,7 @@ tuple_to_list(_Tuple) ->
({allocator_sizes, Alloc}) -> [_] when %% More or less anything
Alloc :: atom();
(build_type) -> opt | debug | purify | quantify | purecov |
- gcov | valgrind | gprof | lcnt;
+ gcov | valgrind | gprof | lcnt | frmptr;
(c_compiler_used) -> {atom(), term()};
(check_io) -> [_];
(compat_rel) -> integer();
@@ -2705,26 +2705,14 @@ port_info(Port, Item) ->
Port :: port() | atom(),
Data :: term().
-port_set_data(Port, Data) ->
- case case erts_internal:port_set_data(Port, Data) of
- Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
- Res -> Res
- end of
- badarg -> erlang:error(badarg, [Port, Data]);
- Result -> Result
- end.
+port_set_data(_Port, _Data) ->
+ erlang:nif_error(undefined).
-spec erlang:port_get_data(Port) -> term() when
Port :: port() | atom().
-port_get_data(Port) ->
- case case erts_internal:port_get_data(Port) of
- Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
- Res -> Res
- end of
- {ok, Data} -> Data;
- Error -> erlang:error(Error, [Port])
- end.
+port_get_data(_Port) ->
+ erlang:nif_error(undefined).
%%
%% If the emulator wants to perform a distributed command and
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
index f1c83f4518..507bc3afb9 100644
--- a/erts/preloaded/src/erts_internal.erl
+++ b/erts/preloaded/src/erts_internal.erl
@@ -31,8 +31,7 @@
-export([await_port_send_result/3]).
-export([port_command/3, port_connect/2, port_close/1,
- port_control/3, port_call/3, port_set_data/2, port_get_data/1,
- port_info/1, port_info/2]).
+ port_control/3, port_call/3, port_info/1, port_info/2]).
%%
%% Await result of send to port
@@ -86,19 +85,6 @@ port_control(_Port, _Operation, _Data) ->
port_call(_Port, _Operation, _Data) ->
erlang:nif_error(undefined).
--spec erts_internal:port_get_data(P1) -> Result when
- P1 :: port() | atom(),
- Result :: {ok, term()} | reference() | badarg.
-port_get_data(_P1) ->
- erlang:nif_error(undefined).
-
--spec erts_internal:port_set_data(P1, P2) -> Result when
- P1 :: port() | atom(),
- P2 :: term(),
- Result :: true | reference() | badarg.
-port_set_data(_P1, _P2) ->
- erlang:nif_error(undefined).
-
-type port_info_1_result_item() ::
{registered_name, RegName :: atom()} |
{id, Index :: non_neg_integer()} |
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 21d23159f0..36a650cb5c 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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
@@ -151,30 +151,35 @@ shutdown_pend_loop(S, N0) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
close(S) when is_port(S) ->
- unlink(S), %% avoid getting {'EXIT', S, Reason}
case subscribe(S, [subs_empty_out_q]) of
{ok, [{subs_empty_out_q,N}]} when N > 0 ->
close_pend_loop(S, N); %% wait for pending output to be sent
_ ->
- catch erlang:port_close(S),
- ok
+ close_port(S)
end.
close_pend_loop(S, N) ->
receive
{empty_out_q,S} ->
- catch erlang:port_close(S), ok
+ close_port(S)
after ?INET_CLOSE_TIMEOUT ->
case getstat(S, [send_pend]) of
{ok, [{send_pend,N1}]} ->
- if N1 =:= N -> catch erlang:port_close(S), ok;
- true -> close_pend_loop(S, N1)
+ if
+ N1 =:= N ->
+ close_port(S);
+ true ->
+ close_pend_loop(S, N1)
end;
_ ->
- catch erlang:port_close(S), ok
+ close_port(S)
end
end.
-
+
+close_port(S) ->
+ catch erlang:port_close(S),
+ receive {'EXIT',S,_} -> ok after 0 -> ok end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% BIND(insock(), IP, Port) -> {ok, integer()} | {error, Reason}
@@ -1072,8 +1077,8 @@ enc_opt(deliver) -> ?INET_LOPT_DELIVER;
enc_opt(exit_on_close) -> ?INET_LOPT_EXITONCLOSE;
enc_opt(high_watermark) -> ?INET_LOPT_TCP_HIWTRMRK;
enc_opt(low_watermark) -> ?INET_LOPT_TCP_LOWTRMRK;
-enc_opt(high_msgq_watermark) -> ?INET_LOPT_TCP_MSGQ_HIWTRMRK;
-enc_opt(low_msgq_watermark) -> ?INET_LOPT_TCP_MSGQ_LOWTRMRK;
+enc_opt(high_msgq_watermark) -> ?INET_LOPT_MSGQ_HIWTRMRK;
+enc_opt(low_msgq_watermark) -> ?INET_LOPT_MSGQ_LOWTRMRK;
enc_opt(send_timeout) -> ?INET_LOPT_TCP_SEND_TIMEOUT;
enc_opt(send_timeout_close) -> ?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE;
enc_opt(delay_send) -> ?INET_LOPT_TCP_DELAY_SEND;
@@ -1128,8 +1133,8 @@ dec_opt(?INET_LOPT_DELIVER) -> deliver;
dec_opt(?INET_LOPT_EXITONCLOSE) -> exit_on_close;
dec_opt(?INET_LOPT_TCP_HIWTRMRK) -> high_watermark;
dec_opt(?INET_LOPT_TCP_LOWTRMRK) -> low_watermark;
-dec_opt(?INET_LOPT_TCP_MSGQ_HIWTRMRK) -> high_msgq_watermark;
-dec_opt(?INET_LOPT_TCP_MSGQ_LOWTRMRK) -> low_msgq_watermark;
+dec_opt(?INET_LOPT_MSGQ_HIWTRMRK) -> high_msgq_watermark;
+dec_opt(?INET_LOPT_MSGQ_LOWTRMRK) -> low_msgq_watermark;
dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT) -> send_timeout;
dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE) -> send_timeout_close;
dec_opt(?INET_LOPT_TCP_DELAY_SEND) -> delay_send;
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index e619408591..76d605569d 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -31,6 +31,23 @@
<p>This document describes the changes made to the asn1 application.</p>
+<section><title>Asn1 2.0.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When an object set is an actual parameter, the extension
+ marker for the object set could get lost (which would
+ cause the decoding of unknown values to fail).</p>
+ <p>
+ Own Id: OTP-10995 Aux Id: seq12290 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 2.0.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 9607799401..33cd3cc4c3 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -134,10 +134,10 @@ $(EBIN)/asn1ct.$(EMULATOR):asn1ct.erl
$(V_ERLC) -b$(EMULATOR) -o$(EBIN) $(ERL_COMPILE_FLAGS) -Dvsn=\"$(VSN)\" $<
$(EBIN)/asn1ct_func.$(EMULATOR): asn1ct_func.erl
- $(ERLC) -o$(EBIN) $(ERL_COMPILE_FLAGS) -I../rt_templates $<
+ $(V_ERLC) -o$(EBIN) $(ERL_COMPILE_FLAGS) -I../rt_templates $<
asn1ct_eval_%.erl: asn1ct_eval_%.funcs
- erl -pa $(EBIN) -noshell -noinput \
+ $(gen_verbose)erl -pa $(EBIN) -noshell -noinput \
-run prepare_templates gen_asn1ct_eval $< >$@
$(APP_TARGET): $(APP_SRC) ../vsn.mk
@@ -182,14 +182,14 @@ RT_TEMPLATES_ERL = $(RT_TEMPLATES:%=%.erl)
RT_TEMPLATES_TARGET = $(RT_TEMPLATES:%=%.$(EMULATOR))
asn1ct_rtt.erl: prepare_templates.$(EMULATOR) $(RT_TEMPLATES_TARGET)
- erl -noshell -noinput -run prepare_templates gen_asn1ct_rtt \
+ $(gen_verbose)erl -noshell -noinput -run prepare_templates gen_asn1ct_rtt \
$(RT_TEMPLATES_TARGET) >asn1ct_rtt.erl
prepare_templates.$(EMULATOR): prepare_templates.erl
- erlc prepare_templates.erl
+ $(V_ERLC) prepare_templates.erl
asn1rtt_%.$(EMULATOR): asn1rtt_%.erl
- erlc +debug_info $<
+ $(V_ERLC) +debug_info $<
$(EVAL_CT_MODULES:%=%.erl): prepare_templates.$(EMULATOR) \
$(EBIN)/asn1ct_rtt.$(EMULATOR)
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index e1911d8170..0622998445 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -1025,8 +1025,8 @@ prepare_objset({{'SingleValue',Set},Ext}) ->
%% {set,lists:append([Set,Ext]),true};
prepare_objset({Set,Ext}) when is_list(Set) ->
{set,merge_sets(Set,Ext),true};
-prepare_objset({ObjDef={object,definedsyntax,_ObjFields},_Ext}) ->
- {set,[ObjDef],true};
+prepare_objset({{object,definedsyntax,_ObjFields}=Set,Ext}) ->
+ {set,merge_sets(Set, Ext),true};
prepare_objset(ObjDef={object,definedsyntax,_ObjFields}) ->
{set,[ObjDef],false};
prepare_objset({ObjDef=#type{},Ext}) when is_list(Ext) ->
@@ -4034,8 +4034,8 @@ categorize(S,value,Type,Value) ->
[#valuedef{type=Type,value=Value,module=S#state.mname}].
-parse_objectset({valueset,T=#type{}}) ->
- [T];
+parse_objectset({valueset,#type{def=#'Externaltypereference'{}=Ref}}) ->
+ Ref;
parse_objectset({valueset,Set}) ->
Set;
parse_objectset(#type{def=Ref}) when is_record(Ref,'Externaltypereference') ->
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index 62418e554e..8deabece37 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -829,8 +829,9 @@ testInfObjectClass(Config, Rule, Opts) ->
testParameterizedInfObj(Config) ->
test(Config, fun testParameterizedInfObj/3).
testParameterizedInfObj(Config, Rule, Opts) ->
- asn1_test_lib:compile("Param", Config, [Rule|Opts]),
- testParameterizedInfObj:main(Rule).
+ Files = ["Param","Param2"],
+ asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
+ testParameterizedInfObj:main(Config, Rule).
testMergeCompile(Config) -> test(Config, fun testMergeCompile/3).
testMergeCompile(Config, Rule, Opts) ->
diff --git a/lib/asn1/test/asn1_SUITE_data/Param2.asn1 b/lib/asn1/test/asn1_SUITE_data/Param2.asn1
new file mode 100644
index 0000000000..09ccb367d8
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/Param2.asn1
@@ -0,0 +1,48 @@
+Param2 DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+ S1AP-PROTOCOL-IES ::= CLASS {
+ &id INTEGER UNIQUE,
+ &Value
+ }
+ WITH SYNTAX {
+ ID &id
+ TYPE &Value
+ }
+
+ ProtocolIE-Field {S1AP-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE {
+ id S1AP-PROTOCOL-IES.&id ({IEsSetParam}),
+ value S1AP-PROTOCOL-IES.&Value ({IEsSetParam}{@id})
+ }
+
+ ProtocolIE-Container {S1AP-PROTOCOL-IES : IEsSetParam} ::=
+ SEQUENCE (SIZE (0..10)) OF ProtocolIE-Field {{IEsSetParam}}
+
+ HandoverRequired ::= SEQUENCE {
+ protocolIEs ProtocolIE-Container { { HandoverRequiredIEs } },
+ ...
+ }
+
+ HandoverRequiredIEs S1AP-PROTOCOL-IES ::= {
+ { ID 1 TYPE OCTET STRING } |
+ { ID 2 TYPE INTEGER },
+--Delete-start
+ ...,
+ { ID 100 TYPE INTEGER (0..1023) } |
+ { ID 101 TYPE ENUMERATED {true,false} }
+--Delete-end
+ }
+
+ SingleRoot ::= SEQUENCE {
+ protocolIEs ProtocolIE-Container { { SingleRootIEs } },
+ ...
+ }
+
+ -- The extension was lost when there was a single root item.
+ SingleRootIEs S1AP-PROTOCOL-IES ::= {
+ { ID 1 TYPE OCTET STRING },
+ ...,
+ { ID 2 TYPE INTEGER }
+ }
+
+END
diff --git a/lib/asn1/test/testParameterizedInfObj.erl b/lib/asn1/test/testParameterizedInfObj.erl
index 17108e285b..212df79fd4 100644
--- a/lib/asn1/test/testParameterizedInfObj.erl
+++ b/lib/asn1/test/testParameterizedInfObj.erl
@@ -20,7 +20,7 @@
-module(testParameterizedInfObj).
--export([main/1,ranap/1]).
+-export([main/2,ranap/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -31,7 +31,11 @@
-record('Iu-ReleaseCommand',{protocolIEs,protocolExtensions}).
-main(Erule) ->
+main(Config, Erule) ->
+ param(Erule),
+ param2(Config, Erule).
+
+param(Erule) ->
PERVal = #'AllocationOrRetentionPriority'
{priorityLevel = true,
iE_Extensions =
@@ -84,7 +88,6 @@ main(Erule) ->
ok.
-
ranap(_Erule) ->
PIEVal2 = [{'ProtocolIE-Field',4,ignore,{radioNetwork,'rab-pre-empted'}}],
?line Val2 =
@@ -102,3 +105,51 @@ open_type(uper,Val) when is_list(Val) ->
list_to_binary(Val);
open_type(_,Val) ->
Val.
+
+param2(Config, Erule) ->
+ roundtrip2('HandoverRequired',
+ {'HandoverRequired',
+ [{'ProtocolIE-Field',1,"ABC"},
+ {'ProtocolIE-Field',2,577799}]}),
+ Enc = roundtrip2('HandoverRequired',
+ {'HandoverRequired',
+ [{'ProtocolIE-Field',1,"ABC"},
+ {'ProtocolIE-Field',2,-42},
+ {'ProtocolIE-Field',100,533},
+ {'ProtocolIE-Field',101,true}]}),
+
+ %% Now remove the data after the extension mark in the object set.
+ DataDir = ?config(data_dir, Config),
+ CaseDir = ?config(case_dir, Config),
+ Asn1SrcBase = "Param2.asn1",
+ Asn1SrcFile0 = filename:join(DataDir, Asn1SrcBase),
+ {ok,Src0} = file:read_file(Asn1SrcFile0),
+ Src = re:replace(Src0, "--Delete-start.*?--Delete-end", "...\n",
+ [dotall,global,{return,binary}]),
+ io:format("~s\n\n", [Src]),
+
+ Asn1SrcFile = filename:join(CaseDir, Asn1SrcBase),
+ ok = file:write_file(Asn1SrcFile, Src),
+ ok = asn1ct:compile(Asn1SrcFile,
+ [{i,DataDir},{outdir,CaseDir},Erule]),
+
+ %% Decompile extended data.
+ {ok,{'HandoverRequired',[{'ProtocolIE-Field',1,"ABC"},
+ {'ProtocolIE-Field',2,-42},
+ {'ProtocolIE-Field',100,Open100},
+ {'ProtocolIE-Field',101,Open101}]}} =
+ asn1_wrapper:decode('Param2', 'HandoverRequired', Enc),
+ true = is_binary(Open100),
+ true = is_binary(Open101),
+
+ %% Test single root.
+ roundtrip2('SingleRoot',
+ {'SingleRoot',[{'ProtocolIE-Field',1,"ABC"},
+ {'ProtocolIE-Field',2,9999}]}),
+ ok.
+
+
+roundtrip2(T, V) ->
+ {ok,Enc} = asn1_wrapper:encode('Param2', T, V),
+ {ok,V} = asn1_wrapper:decode('Param2', T, Enc),
+ Enc.
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index 3c4f3ff122..9245f83280 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1,2 +1,2 @@
#next version number to use is 2.0
-ASN1_VSN = 2.0.1.1
+ASN1_VSN = 2.0.1.2
diff --git a/lib/common_test/priv/ct_default.css b/lib/common_test/priv/ct_default.css
index 1188f8f676..ff48b4fdc0 100644
--- a/lib/common_test/priv/ct_default.css
+++ b/lib/common_test/priv/ct_default.css
@@ -96,6 +96,14 @@ div.ct_error_notify {
margin: .2em 0 0 0;
}
+div.ct_error_notify a:link {
+ color: #D0D0D0;
+}
+
+div.ct_error_notify a:visited {
+ color: #AAAAAA;
+}
+
div.default {
background: lightgreen; color: black;
font-family: "Monaco", "Andale Mono", "Consolas", monospace;
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index c35cbd3c08..9bb9817001 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -599,7 +599,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {file,KeyFile}) ->
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) ->
crypto:start(),
- {K1,K2,K3,IVec} = make_crypto_key(Key),
+ {Key,IVec} = make_crypto_key(Key),
case file:read_file(SrcFileName) of
{ok,Bin0} ->
Bin1 = term_to_binary({SrcFileName,Bin0}),
@@ -607,7 +607,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) ->
0 -> Bin1;
N -> list_to_binary([Bin1,random_bytes(8-N)])
end,
- EncBin = crypto:des3_cbc_encrypt(K1, K2, K3, IVec, Bin2),
+ EncBin = crypto:block_encrypt(des3_cbc, Key, IVec, Bin2),
case file:write_file(EncryptFileName, EncBin) of
ok ->
io:format("~ts --(encrypt)--> ~ts~n",
@@ -638,10 +638,10 @@ decrypt_config_file(EncryptFileName, TargetFileName, {file,KeyFile}) ->
decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) ->
crypto:start(),
- {K1,K2,K3,IVec} = make_crypto_key(Key),
+ {Key,IVec} = make_crypto_key(Key),
case file:read_file(EncryptFileName) of
{ok,Bin} ->
- DecBin = crypto:des3_cbc_decrypt(K1, K2, K3, IVec, Bin),
+ DecBin = crypto:block_decrypt(des3_cbc, Key, IVec, Bin),
case catch binary_to_term(DecBin) of
{'EXIT',_} ->
{error,bad_file};
@@ -713,7 +713,7 @@ get_crypt_key_from_file() ->
make_crypto_key(String) ->
<<K1:8/binary,K2:8/binary>> = First = erlang:md5(String),
<<K3:8/binary,IVec:8/binary>> = erlang:md5([First|lists:reverse(String)]),
- {K1,K2,K3,IVec}.
+ {[K1,K2,K3],IVec}.
random_bytes(N) ->
{A,B,C} = now(),
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index b92fe1555f..276f902b05 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -32,6 +32,7 @@
-export([error_in_suite/1, init_per_suite/1, end_per_suite/1,
init_per_group/2, end_per_group/2]).
+-include("ct.hrl").
-include("ct_event.hrl").
-include("ct_util.hrl").
@@ -806,8 +807,14 @@ error_notification(Mod,Func,_Args,{Error,Loc}) ->
"- - - - - - - - - -~n",
io:format(user, lists:concat([Div,ErrFormat,Div,"~n"]),
ErrArgs),
- ct_logs:tc_log(ct_error_notify, "CT Error Notification",
- ErrFormat, ErrArgs)
+ Link =
+ "\n\n<a href=\"#end\">"
+ "Full error description and stacktrace"
+ "</a>",
+ ct_logs:tc_log(ct_error_notify,
+ ?MAX_IMPORTANCE,
+ "CT Error Notification",
+ ErrFormat++Link, ErrArgs)
end,
case Loc of
[{?MODULE,error_in_suite}] ->
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 752033fdff..f5355bfefe 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -41,7 +41,8 @@
-export([uri/1]).
%% Logging stuff directly from testcase
--export([tc_log/3, tc_log/4, tc_log_async/3, tc_print/3, tc_print/4,
+-export([tc_log/3, tc_log/4, tc_log/5, tc_log_async/3, tc_log_async/5,
+ tc_print/3, tc_print/4,
tc_pal/3, tc_pal/4, ct_log/3, basic_html/0]).
%% Simulate logger process for use without ct environment running
@@ -59,6 +60,7 @@
-define(all_runs_name, "all_runs.html").
-define(index_name, "index.html").
-define(totals_name, "totals.info").
+-define(log_cache_name, "ct_log_cache").
-define(table_color1,"#ADD8E6").
-define(table_color2,"#E4F0FE").
@@ -68,6 +70,10 @@
-define(abs(Name), filename:absname(Name)).
+-record(log_cache, {version,
+ all_runs = [],
+ tests = []}).
+
%%%-----------------------------------------------------------------
%%% @spec init(Mode) -> Result
%%% Mode = normal | interactive
@@ -93,14 +99,25 @@ init(Mode, Verbosity) ->
exit({could_not_start_process,?MODULE,Reason})
end.
-make_dirname({{YY,MM,DD},{H,M,S}}) ->
- io_lib:format(logdir_node_prefix()++".~w-~2.2.0w-~2.2.0w_~2.2.0w.~2.2.0w.~2.2.0w",
- [YY,MM,DD,H,M,S]).
-
+date2str({{YY,MM,DD},{H,M,S}}) ->
+ lists:flatten(io_lib:format("~w-~2.2.0w-~2.2.0w_~2.2.0w.~2.2.0w.~2.2.0w",
+ [YY,MM,DD,H,M,S])).
logdir_prefix() ->
"ct_run".
logdir_node_prefix() ->
- logdir_prefix()++"."++atom_to_list(node()).
+ logdir_prefix() ++ "." ++ atom_to_list(node()).
+
+make_dirname(DateTime) ->
+ logdir_node_prefix() ++ "." ++ date2str(DateTime).
+
+datestr_from_dirname([Y1,Y2,Y3,Y4,$-,Mo1,Mo2,$-,D1,D2,$_,
+ H1,H2,$.,M1,M2,$.,S1,S2 | _]) ->
+ [Y1,Y2,Y3,Y4,$-,Mo1,Mo2,$-,D1,D2,$_,
+ H1,H2,$.,M1,M2,$.,S1,S2];
+datestr_from_dirname([_Ch | Rest]) ->
+ datestr_from_dirname(Rest);
+datestr_from_dirname([]) ->
+ "".
%%%-----------------------------------------------------------------
%%% @spec close(Info, StartDir) -> ok
@@ -108,8 +125,21 @@ logdir_node_prefix() ->
%%% @doc Create index pages with test results and close the CT Log
%%% (tool-internal use only).
close(Info, StartDir) ->
- make_last_run_index(),
-
+ %% close executes on the ct_util process, not on the logger process
+ %% so we need to use a local copy of the log cache data
+ LogCacheBin = make_last_run_index(),
+ put(ct_log_cache,LogCacheBin),
+ Cache2File = fun() ->
+ case get(ct_log_cache) of
+ undefined ->
+ ok;
+ CacheBin ->
+ %% save final version of the log cache to file
+ file:write_file(?log_cache_name,CacheBin),
+ put(ct_log_cache,undefined)
+ end
+ end,
+
ct_event:notify(#event{name=stop_logging,node=node(),data=[]}),
case whereis(?MODULE) of
@@ -132,11 +162,13 @@ close(Info, StartDir) ->
io:format("Warning! Cleanup failed: ~p~n", [Error])
end,
make_all_suites_index(stop),
- make_all_runs_index(stop);
+ make_all_runs_index(stop),
+ Cache2File();
true ->
file:set_cwd(".."),
make_all_suites_index(stop),
make_all_runs_index(stop),
+ Cache2File(),
case ct_util:get_profile_data(browser, StartDir) of
undefined ->
ok;
@@ -168,12 +200,19 @@ clear_stylesheet(TC) ->
%%%-----------------------------------------------------------------
%%% @spec get_log_dir() -> {ok,Dir} | {error,Reason}
get_log_dir() ->
- call({get_log_dir,false}).
+ get_log_dir(false).
%%%-----------------------------------------------------------------
%%% @spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason}
get_log_dir(ReturnAbsName) ->
- call({get_log_dir,ReturnAbsName}).
+ case call({get_log_dir,ReturnAbsName}) of
+ {error,does_not_exist} when ReturnAbsName == true ->
+ {ok,filename:absname(".")};
+ {error,does_not_exist} ->
+ {ok,"."};
+ Result ->
+ Result
+ end.
%%%-----------------------------------------------------------------
%%% make_last_run_index() -> ok
@@ -333,8 +372,15 @@ tc_log(Category,Format,Args) ->
%%%-----------------------------------------------------------------
%%% @spec tc_log(Category,Importance,Format,Args) -> ok
+%%% @equiv tc_log(Category,Importance,"User",Format,Args)
+tc_log(Category,Importance,Format,Args) ->
+ tc_log(Category,Importance,"User",Format,Args).
+
+%%%-----------------------------------------------------------------
+%%% @spec tc_log(Category,Importance,Printer,Format,Args) -> ok
%%% Category = atom()
%%% Importance = integer()
+%%% Printer = string()
%%% Format = string()
%%% Args = list()
%%%
@@ -343,9 +389,6 @@ tc_log(Category,Format,Args) ->
%%% <p>This function is called by <code>ct</code> when logging
%%% stuff directly from a testcase (i.e. not from within the CT
%%% framework).</p>
-tc_log(Category,Importance,Format,Args) ->
- tc_log(Category,Importance,"User",Format,Args).
-
tc_log(Category,Importance,Printer,Format,Args) ->
cast({log,sync,self(),group_leader(),Category,Importance,
[{div_header(Category,Printer),[]},
@@ -355,14 +398,15 @@ tc_log(Category,Importance,Printer,Format,Args) ->
%%%-----------------------------------------------------------------
%%% @spec tc_log_async(Category,Format,Args) -> ok
-%%% @equiv tc_log_async(Category,?STD_IMPORTANCE,Format,Args)
+%%% @equiv tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args)
tc_log_async(Category,Format,Args) ->
- tc_log_async(Category,?STD_IMPORTANCE,Format,Args).
+ tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args).
%%%-----------------------------------------------------------------
%%% @spec tc_log_async(Category,Importance,Format,Args) -> ok
%%% Category = atom()
%%% Importance = integer()
+%%% Printer = string()
%%% Format = string()
%%% Args = list()
%%%
@@ -373,9 +417,9 @@ tc_log_async(Category,Format,Args) ->
%%% to avoid deadlocks when e.g. the hook that handles SASL printouts
%%% prints to the test case log file at the same time test server
%%% asks ct_logs for an html wrapper.</p>
-tc_log_async(Category,Importance,Format,Args) ->
+tc_log_async(Category,Importance,Printer,Format,Args) ->
cast({log,async,self(),group_leader(),Category,Importance,
- [{div_header(Category),[]},
+ [{div_header(Category,Printer),[]},
{Format,Args},
{div_footer(),[]}]}),
ok.
@@ -515,7 +559,6 @@ log_timestamp({MS,S,US}) ->
logger(Parent, Mode, Verbosity) ->
register(?MODULE,self()),
-
%%! Below is a temporary workaround for the limitation of
%%! max one test run per second.
%%! --->
@@ -561,9 +604,10 @@ logger(Parent, Mode, Verbosity) ->
ok ->
case copy_priv_files(PrivFilesSrc, PrivFilesDestRun) of
{error,Src2,Dest2,Reason2} ->
- io:format(user, "ERROR! "++
- "Priv file ~p could not be copied to ~p. "++
- "Reason: ~p~n",
+ io:format(user,
+ "ERROR! "++
+ "Priv file ~p could not be copied to ~p. "
+ ++"Reason: ~p~n",
[Src2,Dest2,Reason2]),
exit({priv_file_error,Dest2});
ok ->
@@ -687,7 +731,7 @@ logger_loop(State) ->
logger_loop(State);
{make_last_run_index,From} ->
make_last_run_index(State#logger_state.start_time),
- return(From,filename:basename(State#logger_state.log_dir)),
+ return(From,get(ct_log_cache)),
logger_loop(State);
{set_stylesheet,_,SSFile} when State#logger_state.stylesheet ==
SSFile ->
@@ -946,40 +990,37 @@ print_style_error(Fd,StyleSheet,Reason) ->
print_style(Fd,undefined).
close_ctlog(Fd) ->
- io:format(Fd,"\n</pre>\n",[]),
- io:format(Fd,footer(),[]),
+ io:format(Fd, "\n</pre>\n", []),
+ io:format(Fd, [xhtml("<br><br>\n", "<br /><br />\n") | footer()], []),
file:close(Fd).
-
%%%-----------------------------------------------------------------
%%% Make an index page for the last run
make_last_run_index(StartTime) ->
IndexName = ?index_name,
AbsIndexName = ?abs(IndexName),
- case catch make_last_run_index1(StartTime,IndexName) of
- {'EXIT', Reason} ->
- io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"),
- io:format("~p~n", [Reason]),
- {error, Reason};
- {error, Reason} ->
- io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"),
- io:format("~p~n", [Reason]),
- {error, Reason};
- ok ->
-% io:put_chars("done\n"),
- ok;
- Err ->
- io:format("Unknown internal error while updating ~ts. "
- "Please report.\n(Err: ~p, ID: 1)",
- [AbsIndexName,Err]),
- {error, Err}
- end.
+ Result =
+ case catch make_last_run_index1(StartTime,IndexName) of
+ {'EXIT', Reason} ->
+ io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"),
+ io:format("~p~n", [Reason]),
+ {error, Reason};
+ {error, Reason} ->
+ io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"),
+ io:format("~p~n", [Reason]),
+ {error, Reason};
+ ok ->
+ ok;
+ Err ->
+ io:format("Unknown internal error while updating ~ts. "
+ "Please report.\n(Err: ~p, ID: 1)",
+ [AbsIndexName,Err]),
+ {error, Err}
+ end,
+ Result.
make_last_run_index1(StartTime,IndexName) ->
- %% this manoeuvre is to ensure the tests get logged
- %% in correct order of time (the 1 sec resolution
- %% of the dirnames may be too big)
Logs1 =
case filelib:wildcard([$*|?logdir_ext]) of
[Log] -> % first test
@@ -1007,7 +1048,8 @@ make_last_run_index1(StartTime,IndexName) ->
0, 0, 0, 0, 0, Missing),
%% write current Totals to file, later to be used in all_runs log
write_totals_file(?totals_name,Label,Logs1,Totals),
- Index = [Index0|index_footer()],
+ Index = [Index0|last_run_index_footer()],
+
case force_write_file(IndexName, unicode:characters_to_binary(Index)) of
ok ->
ok;
@@ -1046,22 +1088,26 @@ make_last_run_index([Name|Rest], Result, TotSucc, TotFail,
TotNotBuilt1, Missing)
end;
-make_last_run_index([], Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, _) ->
- {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, false)],
+make_last_run_index([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt, _) ->
+ {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt, false)],
{TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}}.
make_last_run_index1(SuiteName, [LogDir | LogDirs], Result, TotSucc, TotFail,
UserSkip, AutoSkip, TotNotBuilt, Missing) ->
- case make_one_index_entry(SuiteName, LogDir, "-", false, Missing) of
- {Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
+ case make_one_index_entry(SuiteName, LogDir, "-", false,
+ Missing, undefined) of
+ {Result1,Succ,Fail,USkip,ASkip,NotBuilt,_URIs1} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
{'EXIT',_} -> undefined;
Res -> Res
end,
- make_last_run_index1(SuiteName, LogDirs, [Result|Result1], TotSucc+Succ,
- TotFail+Fail, UserSkip+USkip, AutoSkip1,
- TotNotBuilt+NotBuilt, Missing);
+ make_last_run_index1(SuiteName, LogDirs, [Result|Result1],
+ TotSucc+Succ,
+ TotFail+Fail, UserSkip+USkip, AutoSkip1,
+ TotNotBuilt+NotBuilt, Missing);
error ->
make_last_run_index1(SuiteName, LogDirs, Result, TotSucc, TotFail,
UserSkip, AutoSkip, TotNotBuilt, Missing)
@@ -1070,35 +1116,49 @@ make_last_run_index1(_, [], Result, TotSucc, TotFail,
UserSkip, AutoSkip, TotNotBuilt, _) ->
{Result,TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}.
-make_one_index_entry(SuiteName, LogDir, Label, All, Missing) ->
+make_one_index_entry(SuiteName, LogDir, Label, All, Missing, URIs) ->
case count_cases(LogDir) of
{Succ,Fail,UserSkip,AutoSkip} ->
NotBuilt = not_built(SuiteName, LogDir, All, Missing),
- NewResult = make_one_index_entry1(SuiteName, LogDir, Label, Succ, Fail,
- UserSkip, AutoSkip, NotBuilt, All,
- normal),
- {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt};
+ {NewResult,URIs1} = make_one_index_entry1(SuiteName, LogDir, Label,
+ Succ, Fail,
+ UserSkip, AutoSkip,
+ NotBuilt, All,
+ normal, URIs),
+ {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt,URIs1};
error ->
error
end.
make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
- NotBuilt, All, Mode) ->
+ NotBuilt, All, Mode, URIs) ->
LogFile = filename:join(Link, ?suitelog_name ++ ".html"),
+ CtRunDir = filename:dirname(filename:dirname(Link)),
+ CrashDumpName = SuiteName ++ "_erl_crash.dump",
+
+ URIs1 = {CtRunLogURI,LogFileURI,CrashDumpURI} =
+ case URIs of
+ undefined ->
+ {uri(filename:join(CtRunDir,?ct_log_name)),
+ uri(LogFile),
+ uri(CrashDumpName)};
+ _ ->
+ URIs
+ end,
+
CrashDumpLink = case Mode of
- cached ->
+ temp ->
"";
normal ->
- CrashDumpName = SuiteName ++ "_erl_crash.dump",
case filelib:is_file(CrashDumpName) of
true ->
- ["&nbsp;<a href=\"", uri(CrashDumpName),
+ ["&nbsp;<a href=\"", CrashDumpURI,
"\">(CrashDump)</a>"];
false ->
""
end
end,
- CtRunDir = filename:dirname(filename:dirname(Link)),
+
{Lbl,Timestamp,Node,AllInfo} =
case All of
{true,OldRuns} ->
@@ -1107,7 +1167,9 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
0 -> "-";
_ -> NodeOrDate
end,
+
TS = timestamp(CtRunDir),
+
N = xhtml(["<td align=right><font size=\"-1\">",Node1,
"</font></td>\n"],
["<td align=right>",Node1,"</td>\n"]),
@@ -1116,28 +1178,31 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
["<td align=center><b>",Label,"</b></td>\n"]),
T = xhtml(["<td><font size=\"-1\">",TS,"</font></td>\n"],
["<td>",TS,"</td>\n"]),
- CtLogFile = filename:join(CtRunDir,?ct_log_name),
+
OldRunsLink =
case OldRuns of
[] -> "none";
_ -> "<a href=\""++?all_runs_name++"\">Old Runs</a>"
end,
- A = xhtml(["<td><font size=\"-1\"><a href=\"",uri(CtLogFile),
+
+ A = xhtml(["<td><font size=\"-1\"><a href=\"",CtRunLogURI,
"\">CT Log</a></font></td>\n",
- "<td><font size=\"-1\">",OldRunsLink,"</font></td>\n"],
- ["<td><a href=\"",uri(CtLogFile),"\">CT Log</a></td>\n",
+ "<td><font size=\"-1\">",OldRunsLink,
+ "</font></td>\n"],
+ ["<td><a href=\"",CtRunLogURI,
+ "\">CT Log</a></td>\n",
"<td>",OldRunsLink,"</td>\n"]),
{L,T,N,A};
false ->
{"","","",""}
end,
+
NotBuiltStr =
if NotBuilt == 0 ->
["<td align=right>",integer_to_list(NotBuilt),"</td>\n"];
true ->
- ["<td align=right><a href=\"",
- uri(filename:join(CtRunDir,?ct_log_name)),"\">",
- integer_to_list(NotBuilt),"</a></td>\n"]
+ ["<td align=right><a href=\"",CtRunLogURI,"\">",
+ integer_to_list(NotBuilt),"</a></td>\n"]
end,
FailStr =
if Fail > 0 ->
@@ -1156,17 +1221,17 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
end,
{UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
end,
- [xhtml("<tr valign=top>\n",
- ["<tr class=\"",odd_or_even(),"\">\n"]),
- xhtml("<td><font size=\"-1\"><a href=\"", "<td><a href=\""),
- uri(LogFile),"\">",SuiteName,"</a>", CrashDumpLink,
- xhtml("</font></td>\n", "</td>\n"),
- Lbl, Timestamp,
- "<td align=right>",integer_to_list(Success),"</td>\n",
- "<td align=right>",FailStr,"</td>\n",
- "<td align=right>",integer_to_list(AllSkip),
- " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
- NotBuiltStr, Node, AllInfo, "</tr>\n"].
+ {[xhtml("<tr valign=top>\n",
+ ["<tr class=\"",odd_or_even(),"\">\n"]),
+ xhtml("<td><font size=\"-1\"><a href=\"", "<td><a href=\""),
+ LogFileURI,"\">",SuiteName,"</a>", CrashDumpLink,
+ xhtml("</font></td>\n", "</td>\n"),
+ Lbl, Timestamp,
+ "<td align=right>",integer_to_list(Success),"</td>\n",
+ "<td align=right>",FailStr,"</td>\n",
+ "<td align=right>",integer_to_list(AllSkip),
+ " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
+ NotBuiltStr, Node, AllInfo, "</tr>\n"], URIs1}.
total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) ->
{Label,TimestampCell,AllInfo} =
@@ -1392,17 +1457,30 @@ header1(Title, SubTitle, TableCols) ->
"</center>\n",
SubTitleHTML,"\n"].
-index_footer() ->
- ["</table>\n"
+last_run_index_footer() ->
+ AllRuns = filename:join("../",?all_runs_name),
+ TestIndex = filename:join("../",?index_name),
+ ["</table>\n",
+ xhtml("<br><hr><p>\n", "<br /><hr /><p>\n"),
+ "<a href=\"", uri(AllRuns),
+ "\">Test run history\n</a> | ",
+ "<a href=\"", uri(TestIndex),
+ "\">Top level test index\n</a>\n</p>\n",
"</center>\n" | footer()].
+all_suites_index_footer() ->
+ ["</table>\n",
+ "</center>\n",
+ xhtml("<br><br>\n", "<br /><br />\n") | footer()].
+
all_runs_index_footer() ->
- ["</tbody>\n</table>\n"
- "</center>\n" | footer()].
+ ["</tbody>\n</table>\n",
+ "</center>\n",
+ xhtml("<br><br>\n", "<br /><br />\n") | footer()].
footer() ->
["<center>\n",
- xhtml("<br><br>\n<hr>\n", "<br /><br />\n"),
+ xhtml("<hr>\n", ""),
xhtml("<p><font size=\"-1\">\n", "<div class=\"copyright\">"),
"Copyright &copy; ", year(),
" <a href=\"http://www.erlang.org\">Open Telecom Platform</a>",
@@ -1414,7 +1492,6 @@ footer() ->
"</body>\n"
"</html>\n"].
-
body_tag() ->
CTPath = code:lib_dir(common_test),
TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
@@ -1580,35 +1657,169 @@ make_all_runs_index(When) ->
if When == start -> ok;
true -> io:put_chars("Updating " ++ AbsName ++ "... ")
end,
+
+ %% check if log cache should be used, and if it exists
+ UseCache =
+ if When == refresh ->
+ save_only;
+ true ->
+ case application:get_env(common_test, disable_log_cache) of
+ {ok,true} ->
+ disabled;
+ _ ->
+ case get(ct_log_cache) of
+ undefined ->
+ file:read_file(?log_cache_name);
+ LogCacheBin ->
+ {ok,LogCacheBin}
+ end
+ end
+ end,
+
Dirs = filelib:wildcard(logdir_prefix()++"*.*"),
DirsSorted = (catch sort_all_runs(Dirs)),
- Header = all_runs_header(),
- Index = [runentry(Dir) || Dir <- DirsSorted],
- Result = file:write_file(AbsName,
- unicode:characters_to_binary(
- Header++Index++all_runs_index_footer())),
+
+ LogCacheInfo = get_cache_data(UseCache),
+
+ Result =
+ case LogCacheInfo of
+ {ok,LogCache} ->
+ %% use the log cache file to generate the index
+ make_all_runs_from_cache(AbsName,DirsSorted,LogCache);
+
+ _WhyNot ->
+ %% no cache file exists (or feature has been disabled)
+ Header = all_runs_header(),
+ GetLogResult =
+ fun(Dir,{RunData,LogTxt}) ->
+ {Tot,XHTML,IxLink} = runentry(Dir,
+ undefined,
+ undefined),
+ {[{Dir,Tot,IxLink}|RunData],[XHTML|LogTxt]}
+ end,
+ {AllRunsData,Index} =
+ lists:foldr(GetLogResult,{[],[]},DirsSorted),
+
+ %% update cache with result unless the cache is disabled
+ if UseCache == disabled -> ok;
+ true -> update_all_runs_in_cache(AllRunsData)
+ end,
+ %% write all_runs log file
+ ok = file:write_file(AbsName,
+ unicode:characters_to_binary(
+ Header++Index++
+ all_runs_index_footer()))
+ end,
+ notify_and_unlock_file(AbsName),
if When == start -> ok;
true -> io:put_chars("done\n")
end,
- notify_and_unlock_file(AbsName),
Result.
+make_all_runs_from_cache(AbsName, Dirs, LogCache) ->
+ Header = all_runs_header(),
+
+ %% Note that both Dirs and the cache is sorted!
+ AllRunsDirs = dir_diff_all_runs(Dirs, LogCache),
+
+ GetLogResult =
+ fun({Dir,no_test_data,IxLink},{RunData,LogTxt}) ->
+ {Tot,XHTML,_} = runentry(Dir,undefined,IxLink),
+ {[{Dir,Tot,IxLink}|RunData],[XHTML|LogTxt]};
+ ({Dir,CachedTotals,IxLink},{RunData,LogTxt}) ->
+ %% create log entry using cached data
+ {Tot,XHTML,_} = runentry(Dir,CachedTotals,IxLink),
+ {[{Dir,Tot,IxLink}|RunData],[XHTML|LogTxt]};
+ (Dir,{RunData,LogTxt}) ->
+ %% create log entry from scratch
+ {Tot,XHTML,IxLink} = runentry(Dir,undefined,undefined),
+ {[{Dir,Tot,IxLink}|RunData],[XHTML|LogTxt]}
+ end,
+ {AllRunsData,Index} = lists:foldr(GetLogResult,{[],[]},AllRunsDirs),
+ %% update cache with result
+ update_all_runs_in_cache(AllRunsData,LogCache),
+ %% write all_runs log file
+ ok = file:write_file(AbsName,
+ unicode:characters_to_binary(
+ Header++Index++
+ all_runs_index_footer())).
+
+update_all_runs_in_cache(AllRunsData) ->
+ case get(ct_log_cache) of
+ undefined ->
+ LogCache = #log_cache{version = cache_vsn(),
+ all_runs = AllRunsData},
+ case {self(),whereis(?MODULE)} of
+ {_Pid,_Pid} ->
+ %% save the cache in RAM so it doesn't have to be
+ %% read from file as long as this logger process is alive
+ put(ct_log_cache,term_to_binary(LogCache));
+ _ ->
+ file:write_file(?log_cache_name,term_to_binary(LogCache))
+ end;
+ SavedLogCache ->
+ update_all_runs_in_cache(AllRunsData,binary_to_term(SavedLogCache))
+ end.
+
+update_all_runs_in_cache(AllRunsData, LogCache) ->
+ LogCache1 = LogCache#log_cache{all_runs = AllRunsData},
+ case {self(),whereis(?MODULE)} of
+ {_Pid,_Pid} ->
+ %% save the cache in RAM so it doesn't have to be
+ %% read from file as long as this logger process is alive
+ put(ct_log_cache,term_to_binary(LogCache1));
+ _ ->
+ file:write_file(?log_cache_name,term_to_binary(LogCache1))
+ end.
+
sort_all_runs(Dirs) ->
%% sort on time string, always last and on the format:
%% "YYYY-MM-DD_HH.MM.SS"
- KeyList =
- lists:map(fun(Dir) ->
- case lists:reverse(string:tokens(Dir,[$.,$_])) of
- [SS,MM,HH,Date|_] ->
- {{Date,HH,MM,SS},Dir};
- _Other ->
- throw(Dirs)
- end
- end,Dirs),
- lists:reverse(lists:map(fun({_,Dir}) ->
- Dir
- end,lists:keysort(1,KeyList))).
+ lists:sort(fun(Dir1,Dir2) ->
+ [SS1,MM1,HH1,Date1|_] =
+ lists:reverse(string:tokens(Dir1,[$.,$_])),
+ [SS2,MM2,HH2,Date2|_] =
+ lists:reverse(string:tokens(Dir2,[$.,$_])),
+ {Date1,HH1,MM1,SS1} > {Date2,HH2,MM2,SS2}
+ end, Dirs).
+
+dir_diff_all_runs(Dirs, LogCache) ->
+ case LogCache#log_cache.all_runs of
+ [] ->
+ Dirs;
+ Cached = [{CDir,_,_}|_] ->
+ AllRunsDirs =
+ dir_diff_all_runs(Dirs, Cached, datestr_from_dirname(CDir), []),
+ lists:reverse(AllRunsDirs)
+ end.
+
+dir_diff_all_runs(LogDirs=[Dir|Dirs], Cached=[CElem|CElems],
+ LatestInCache, AllRunsDirs) ->
+ DirDate = datestr_from_dirname(Dir),
+ if DirDate > LatestInCache ->
+ %% Dir is a new run entry
+ dir_diff_all_runs(Dirs, Cached, LatestInCache,
+ [Dir|AllRunsDirs]);
+ DirDate == LatestInCache, CElems /= [] ->
+ %% Dir is an existing run entry
+ dir_diff_all_runs(Dirs, CElems,
+ datestr_from_dirname(element(1,hd(CElems))),
+ [CElem|AllRunsDirs]);
+ DirDate == LatestInCache, CElems == [] ->
+ %% we're done, Dirs must all be new
+ lists:reverse(Dirs)++[CElem|AllRunsDirs];
+ CElems /= [] -> % DirDate < LatestInCache
+ %% current CDir not in Dirs, update timestamp and check next
+ dir_diff_all_runs(LogDirs, CElems,
+ datestr_from_dirname(element(1,hd(CElems))),
+ AllRunsDirs);
+ CElems == [] ->
+ %% we're done, LogDirs must all be new
+ lists:reverse(LogDirs)++AllRunsDirs
+ end;
+dir_diff_all_runs([], _Cached, _, AllRunsDirs) ->
+ AllRunsDirs.
interactive_link() ->
[Dir|_] = lists:reverse(filelib:wildcard(logdir_prefix()++"*.*")),
@@ -1619,12 +1830,14 @@ interactive_link() ->
"<html>\n"],
["<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n",
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n",
- "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"]),
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" ",
+ "xml:lang=\"en\" lang=\"en\">\n"]),
"<!-- autogenerated by '"++atom_to_list(?MODULE)++"' -->\n",
"<head>\n",
"<title>Last interactive run</title>\n",
"<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
- "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n",
+ "<meta http-equiv=\"content-type\" content=\"text/html; "
+ "charset=utf-8\">\n",
"</head>\n",
"<body>\n",
"Log from last interactive run: <a href=\"",uri(CtLog),"\">",
@@ -1637,98 +1850,120 @@ interactive_link() ->
"Any CT activities will be logged here\n",
[?abs("last_interactive.html")]).
-runentry(Dir) ->
+%% use if cache disabled or non-existing
+runentry(Dir, undefined, _) ->
TotalsFile = filename:join(Dir,?totals_name),
- TotalsStr =
- case read_totals_file(TotalsFile) of
- {Node,Label,Logs,{TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}} ->
- TotFailStr =
- if TotFail > 0 ->
- ["<font color=\"red\">",
- integer_to_list(TotFail),"</font>"];
- true ->
- integer_to_list(TotFail)
- end,
- {AllSkip,UserSkipStr,AutoSkipStr} =
- if AutoSkip == undefined -> {UserSkip,"?","?"};
- true ->
- ASStr = if AutoSkip > 0 ->
- ["<font color=\"brown\">",
- integer_to_list(AutoSkip),"</font>"];
- true -> integer_to_list(AutoSkip)
- end,
- {UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
- end,
- NoOfTests = case length(Logs) of
- 0 -> "-";
- N -> integer_to_list(N)
- end,
- StripExt =
- fun(File) ->
- string:sub_string(File,1,
- length(File)-
- length(?logdir_ext)) ++ ", "
- end,
- Polish = fun(S) -> case lists:reverse(S) of
- [32,$,|Rev] -> lists:reverse(Rev);
- [$,|Rev] -> lists:reverse(Rev);
- _ -> S
- end
- end,
- TestNames = Polish(lists:flatten(lists:map(StripExt,Logs))),
- TestNamesTrunc =
- if TestNames=="" ->
- "";
- length(TestNames) < ?testname_width ->
- TestNames;
- true ->
- Trunc = Polish(string:substr(TestNames,1,?testname_width-3)),
- lists:flatten(io_lib:format("~ts...",[Trunc]))
- end,
- Total = TotSucc+TotFail+AllSkip,
- A = xhtml(["<td align=center><font size=\"-1\">",Node,
- "</font></td>\n",
- "<td align=center><font size=\"-1\"><b>",Label,
- "</b></font></td>\n",
- "<td align=right>",NoOfTests,"</td>\n"],
- ["<td align=center>",Node,"</td>\n",
- "<td align=center><b>",Label,"</b></td>\n",
- "<td align=right>",NoOfTests,"</td>\n"]),
- B = xhtml(["<td align=center title='",TestNames,"'><font size=\"-1\"> ",
- TestNamesTrunc,"</font></td>\n"],
- ["<td align=center title='",TestNames,"'> ",
- TestNamesTrunc,"</td>\n"]),
- C = ["<td align=right>",integer_to_list(Total),"</td>\n",
- "<td align=right>",integer_to_list(TotSucc),"</td>\n",
- "<td align=right>",TotFailStr,"</td>\n",
- "<td align=right>",integer_to_list(AllSkip),
- " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
- "<td align=right>",integer_to_list(NotBuilt),"</td>\n"],
- A++B++C;
- _ ->
- A = xhtml(["<td align=center><font size=\"-1\" color=\"red\">"
- "Test data missing or corrupt</font></td>\n",
- "<td align=center><font size=\"-1\">?</font></td>\n",
- "<td align=right>?</td>\n"],
- ["<td align=center><font color=\"red\">"
- "Test data missing or corrupt</font></td>\n",
- "<td align=center>?</td>\n",
- "<td align=right>?</td>\n"]),
- B = xhtml(["<td align=center><font size=\"-1\">?</font></td>\n"],
- ["<td align=center>?</td>\n"]),
- C = ["<td align=right>?</td>\n",
- "<td align=right>?</td>\n",
- "<td align=right>?</td>\n",
- "<td align=right>?</td>\n",
- "<td align=right>?</td>\n"],
- A++B++C
- end,
Index = uri(filename:join(Dir,?index_name)),
- [xhtml("<tr>\n", ["<tr class=\"",odd_or_even(),"\">\n"]),
- xhtml(["<td><font size=\"-1\"><a href=\"",Index,"\">",timestamp(Dir),"</a>",
- TotalsStr,"</font></td>\n"],
- ["<td><a href=\"",Index,"\">",timestamp(Dir),"</a>",TotalsStr,"</td>\n"]),
- "</tr>\n"].
+ runentry(Dir, read_totals_file(TotalsFile), Index);
+
+%% use cached data
+runentry(Dir, Totals={Node,Label,Logs,
+ {TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}}, Index) ->
+ TotFailStr =
+ if TotFail > 0 ->
+ ["<font color=\"red\">",
+ integer_to_list(TotFail),"</font>"];
+ true ->
+ integer_to_list(TotFail)
+ end,
+ {AllSkip,UserSkipStr,AutoSkipStr} =
+ if AutoSkip == undefined -> {UserSkip,"?","?"};
+ true ->
+ ASStr = if AutoSkip > 0 ->
+ ["<font color=\"brown\">",
+ integer_to_list(AutoSkip),
+ "</font>"];
+ true -> integer_to_list(AutoSkip)
+ end,
+ {UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
+ end,
+ NoOfTests = case length(Logs) of
+ 0 -> "-";
+ N -> integer_to_list(N)
+ end,
+ StripExt =
+ fun(File) ->
+ string:sub_string(File,1,
+ length(File)-
+ length(?logdir_ext)) ++ ", "
+ end,
+ Polish = fun(S) -> case lists:reverse(S) of
+ [32,$,|Rev] -> lists:reverse(Rev);
+ [$,|Rev] -> lists:reverse(Rev);
+ _ -> S
+ end
+ end,
+ TestNames = Polish(lists:flatten(lists:map(StripExt,Logs))),
+ TestNamesTrunc =
+ if TestNames=="" ->
+ "";
+ length(TestNames) < ?testname_width ->
+ TestNames;
+ true ->
+ Trunc = Polish(string:substr(TestNames,1,
+ ?testname_width-3)),
+ lists:flatten(io_lib:format("~ts...",[Trunc]))
+ end,
+ Total = TotSucc+TotFail+AllSkip,
+ A = xhtml(["<td align=center><font size=\"-1\">",Node,
+ "</font></td>\n",
+ "<td align=center><font size=\"-1\"><b>",Label,
+ "</b></font></td>\n",
+ "<td align=right>",NoOfTests,"</td>\n"],
+ ["<td align=center>",Node,"</td>\n",
+ "<td align=center><b>",Label,"</b></td>\n",
+ "<td align=right>",NoOfTests,"</td>\n"]),
+ B = xhtml(["<td align=center title='",TestNames,
+ "'><font size=\"-1\"> ",
+ TestNamesTrunc,"</font></td>\n"],
+ ["<td align=center title='",TestNames,"'> ",
+ TestNamesTrunc,"</td>\n"]),
+ C = ["<td align=right>",integer_to_list(Total),"</td>\n",
+ "<td align=right>",integer_to_list(TotSucc),"</td>\n",
+ "<td align=right>",TotFailStr,"</td>\n",
+ "<td align=right>",integer_to_list(AllSkip),
+ " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
+ "<td align=right>",integer_to_list(NotBuilt),"</td>\n"],
+ TotalsStr = A++B++C,
+
+ XHTML = [xhtml("<tr>\n", ["<tr class=\"",odd_or_even(),"\">\n"]),
+ xhtml(["<td><font size=\"-1\"><a href=\"",Index,"\">",
+ timestamp(Dir),"</a>",
+ TotalsStr,"</font></td>\n"],
+ ["<td><a href=\"",Index,"\">",timestamp(Dir),"</a>",TotalsStr,
+ "</td>\n"]),
+ "</tr>\n"],
+ {Totals,XHTML,Index};
+
+%% handle missing or corrupt data (missing e.g. if the test is in progress)
+runentry(Dir, _, _) ->
+ A = xhtml(["<td align=center><font size=\"-1\" color=\"red\">"
+ "Test data missing or corrupt</font></td>\n",
+ "<td align=center><font size=\"-1\">?</font></td>\n",
+ "<td align=right>?</td>\n"],
+ ["<td align=center><font color=\"red\">"
+ "Test data missing or corrupt</font></td>\n",
+ "<td align=center>?</td>\n",
+ "<td align=right>?</td>\n"]),
+ B = xhtml(["<td align=center><font size=\"-1\">?</font></td>\n"],
+ ["<td align=center>?</td>\n"]),
+ C = ["<td align=right>?</td>\n",
+ "<td align=right>?</td>\n",
+ "<td align=right>?</td>\n",
+ "<td align=right>?</td>\n",
+ "<td align=right>?</td>\n"],
+ TotalsStr = A++B++C,
+
+ Index = uri(filename:join(Dir,?index_name)),
+
+ XHTML = [xhtml("<tr>\n", ["<tr class=\"",odd_or_even(),"\">\n"]),
+ xhtml(["<td><font size=\"-1\"><a href=\"",Index,"\">",
+ timestamp(Dir),"</a>",
+ TotalsStr,"</font></td>\n"],
+ ["<td><a href=\"",Index,"\">",timestamp(Dir),"</a>",TotalsStr,
+ "</td>\n"]),
+ "</tr>\n"],
+ {no_test_data,XHTML,Index}.
write_totals_file(Name,Label,Logs,Totals) ->
AbsName = ?abs(Name),
@@ -1755,17 +1990,19 @@ read_totals_file(Name) ->
_ -> Label
end,
case Tot of
- {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
+ {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
{Node,Label1,Ls,Tot};
{TotSucc,TotFail,AllSkip,NotBuilt} ->
- {Node,Label1,Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
+ {Node,Label1,Ls,
+ {TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
end;
{Node,Ls,Tot} -> % no label found
case Tot of
- {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
+ {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
{Node,"-",Ls,Tot};
{TotSucc,TotFail,AllSkip,NotBuilt} ->
- {Node,"-",Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
+ {Node,"-",Ls,
+ {TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
end;
%% for backwards compatibility
{Ls,Tot} -> {"-",Ls,Tot};
@@ -1819,29 +2056,73 @@ timestamp(Dir) ->
%% run will not show until after the final refresh.
%% -------------------------------------------------------------------------
-%% Creates the top level index file. When == start | refresh.
-%% A copy of the dir tree under logdir is cached as a result.
+%% Creates the top level index file. When == start | stop | refresh.
+%% A copy of the dir tree under logdir is saved temporarily as a result.
make_all_suites_index(When) when is_atom(When) ->
put(basic_html, basic_html()),
AbsIndexName = ?abs(?index_name),
notify_and_lock_file(AbsIndexName),
+
+ %% check if log cache should be used, and if it exists
+ UseCache =
+ if When == refresh ->
+ save_only;
+ true ->
+ case application:get_env(common_test, disable_log_cache) of
+ {ok,true} ->
+ disabled;
+ _ ->
+ case get(ct_log_cache) of
+ undefined ->
+ file:read_file(?log_cache_name);
+ LogCacheBin ->
+ {ok,LogCacheBin}
+ end
+ end
+ end,
+
LogDirs = filelib:wildcard(logdir_prefix()++".*/*"++?logdir_ext),
- Sorted = sort_logdirs(LogDirs, []),
- Result = make_all_suites_index1(When, AbsIndexName, Sorted),
- notify_and_unlock_file(AbsIndexName),
- Result;
-%% This updates the top level index file using cached data from
-%% the initial index file creation.
-make_all_suites_index(NewTestData = {_TestName,DirName}) ->
+ LogCacheInfo = get_cache_data(UseCache),
+
+ Result =
+ case LogCacheInfo of
+ {ok,LogCache} ->
+ %% use the log cache file to generate the index
+ make_all_suites_index_from_cache(When,AbsIndexName,
+ LogDirs,LogCache);
+ _WhyNot ->
+ %% no cache file exists (or feature has been disabled)
+ Sorted = sort_and_filter_logdirs(LogDirs),
+ TempData = make_all_suites_index1(When,AbsIndexName,Sorted),
+ notify_and_unlock_file(AbsIndexName),
+
+ %% save new cache file unless the feature is disabled
+ if UseCache == disabled -> ok;
+ true -> update_tests_in_cache(TempData)
+ end,
+ TempData
+ end,
+
+ case Result of
+ Error = {error,_} -> Error;
+ _ -> ok
+ end;
+
+%% This updates the top level index file using data from the initial
+%% index file creation, saved temporarily in a table.
+make_all_suites_index(NewTestData = {_TestName,DirName}) ->
put(basic_html, basic_html()),
- %% AllLogDirs = [{TestName,Label,Missing,{LastLogDir,Summary},OldDirs}|...]
+
+ %% AllLogDirs = [{TestName,Label,Missing,
+ %% {LastLogDir,Summary,URIs},OldDirs}|...]
+
{AbsIndexName,LogDirData} = ct_util:get_testdata(test_index),
CtRunDirPos = length(filename:split(AbsIndexName)),
CtRunDir = filename:join(lists:sublist(filename:split(DirName),
CtRunDirPos)),
-
+
Label = case read_totals_file(filename:join(CtRunDir, ?totals_name)) of
{_,"-",_,_} -> "...";
{_,Lbl,_,_} -> Lbl;
@@ -1849,10 +2130,10 @@ make_all_suites_index(NewTestData = {_TestName,DirName}) ->
end,
notify_and_lock_file(AbsIndexName),
Result =
- case catch make_all_suites_ix_cached(AbsIndexName,
- NewTestData,
- Label,
- LogDirData) of
+ case catch make_all_suites_ix_temp(AbsIndexName,
+ NewTestData,
+ Label,
+ LogDirData) of
{'EXIT',Reason} ->
io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"),
io:format("~p~n", [Reason]),
@@ -1869,46 +2150,219 @@ make_all_suites_index(NewTestData = {_TestName,DirName}) ->
[AbsIndexName,Err]),
{error, Err}
end,
- notify_and_unlock_file(AbsIndexName),
+ notify_and_unlock_file(AbsIndexName),
Result.
-sort_logdirs([Dir|Dirs],Groups) ->
+make_all_suites_index_from_cache(When, AbsIndexName, LogDirs, LogCache) ->
+
+ %% The structure of the cache:
+ %%
+ %% #log_cache{tests = {TestName,Label,Missing,
+ %% {LastLogDir,Summary,URIs},OldDirs}
+ %% }
+ %% Summary = {Succ,Fail,USkip,ASkip} | error
+ %%
+
+ {NewAdded,OldTests} = dir_diff_tests(LogDirs,LogCache),
+
+ LogCache1 = delete_tests_from_cache(OldTests,LogCache),
+ Sorted = sort_and_filter_logdirs(NewAdded,
+ LogCache1#log_cache.tests),
+ TempData =
+ if Sorted /= [] ->
+ make_all_suites_index1(When,AbsIndexName,
+ Sorted);
+ true ->
+ Data = LogCache1#log_cache.tests,
+ ct_util:set_testdata_async({test_index,{AbsIndexName,
+ Data}}),
+ Data
+ end,
+
+ notify_and_unlock_file(AbsIndexName),
+
+ update_tests_in_cache(TempData,LogCache1),
+ TempData.
+
+sort_and_filter_logdirs(NewDirs,CachedTests) when CachedTests /= [] ->
+ NewSorted = sort_and_filter_logdirs1(NewDirs,[]),
+ sort_and_filter_logdirs(NewSorted,CachedTests,[]);
+
+sort_and_filter_logdirs(NewDirs,_CachedTests) ->
+ sort_and_filter_logdirs(NewDirs).
+
+%% sort latest dirs found and combine them with cached entries
+sort_and_filter_logdirs([{TestName,IxDirs}|Tests],CachedTests,Combined) ->
+ case lists:keysearch(TestName,1,CachedTests) of
+ {value,{TestName,_,_,{IxDir0,_,_},IxDirs0}} ->
+ Groups = sort_and_filter_logdirs2(TestName,
+ IxDirs++[IxDir0|IxDirs0],
+ []),
+ sort_and_filter_logdirs(Tests,CachedTests,Groups++Combined);
+ _ ->
+ IxDirs1 = lists:map(fun(Elem = {_,_}) ->
+ Elem;
+ (RunDir) ->
+ {filename:basename(RunDir),RunDir}
+ end, IxDirs),
+ sort_and_filter_logdirs(Tests,CachedTests,
+ [{TestName,IxDirs1}|Combined])
+ end;
+sort_and_filter_logdirs([],CachedTests,Combined) ->
+ Cached1 = lists:foldl(fun({TestName,_},Cached) ->
+ lists:keydelete(TestName,1,Cached)
+ end, CachedTests, Combined),
+ lists:keysort(1,sort_each_group(Combined)++Cached1).
+
+sort_and_filter_logdirs(Dirs) ->
+ sort_and_filter_logdirs1(Dirs, []).
+
+%% sort and filter directories (no cache)
+sort_and_filter_logdirs1([Dir|Dirs],Groups) ->
TestName = filename:rootname(filename:basename(Dir)),
case filelib:wildcard(filename:join(Dir,"run.*")) of
RunDirs = [_|_] ->
- Groups1 = sort_logdirs1(TestName,RunDirs,Groups),
- sort_logdirs(Dirs,Groups1);
+ Groups1 = sort_and_filter_logdirs2(TestName,RunDirs,Groups),
+ sort_and_filter_logdirs1(Dirs,Groups1);
_ -> % ignore missing run directory
- sort_logdirs(Dirs,Groups)
+ sort_and_filter_logdirs1(Dirs,Groups)
end;
-sort_logdirs([],Groups) ->
+sort_and_filter_logdirs1([],Groups) ->
lists:keysort(1,sort_each_group(Groups)).
-sort_logdirs1(TestName,[RunDir|RunDirs],Groups) ->
+sort_and_filter_logdirs2(TestName,[RunDir|RunDirs],Groups) ->
Groups1 = insert_test(TestName,{filename:basename(RunDir),RunDir},Groups),
- sort_logdirs1(TestName,RunDirs,Groups1);
-sort_logdirs1(_,[],Groups) ->
+ sort_and_filter_logdirs2(TestName,RunDirs,Groups1);
+sort_and_filter_logdirs2(_,[],Groups) ->
Groups.
+%% new rundir for Test found, add to (not sorted) list of prev rundirs
insert_test(Test,IxDir,[{Test,IxDirs}|Groups]) ->
[{Test,[IxDir|IxDirs]}|Groups];
+%% first occurance of Test
insert_test(Test,IxDir,[]) ->
[{Test,[IxDir]}];
insert_test(Test,IxDir,[TestDir|Groups]) ->
[TestDir|insert_test(Test,IxDir,Groups)].
-
+
+%% sort the list of rundirs for each Test
sort_each_group([{Test,IxDirs}|Groups]) ->
Sorted = lists:reverse([Dir || {_,Dir} <- lists:keysort(1,IxDirs)]),
- [{Test,Sorted}| sort_each_group(Groups)];
+ [{Test,Sorted}|sort_each_group(Groups)];
sort_each_group([]) ->
[].
-make_all_suites_index1(When, AbsIndexName, AllLogDirs) ->
+dir_diff_tests(LogDirs, #log_cache{tests = CachedTests}) ->
+ AllTestNames =
+ [TestName || {TestName,_,_,_,_} <- CachedTests],
+ dir_diff_tests(LogDirs, CachedTests, [], AllTestNames, [], []).
+
+dir_diff_tests([LogDir|LogDirs], CachedTests, NewAdded, DeletedTests,
+ ValidLast, InvalidLast) ->
+ TestName = filename:rootname(filename:basename(LogDir)),
+ Time = datestr_from_dirname(LogDir),
+ %% check if the test already exists in the cache
+ {New,DeletedTests1,ValidLast1,InvalidLast1} =
+ case lists:keysearch(TestName,1,CachedTests) of
+ {value,{_,_,_,{LastLogDir,_,_},_PrevLogDirs}} ->
+ LastLogTime = datestr_from_dirname(LastLogDir),
+ if Time > LastLogTime ->
+ %% this is a new test run, not in cache
+ {[LogDir|NewAdded],
+ lists:delete(TestName,DeletedTests),
+ ValidLast,[{TestName,LastLogDir}|InvalidLast]};
+ Time == LastLogTime ->
+ %% this is the latest test run, already in cache
+ TDir = {TestName,LastLogDir},
+ {NewAdded,
+ lists:delete(TestName,DeletedTests),
+ [TDir|ValidLast],InvalidLast};
+ true ->
+ %% this is an old test run
+ {[],
+ lists:delete(TestName,DeletedTests),
+ ValidLast,[{TestName,LastLogDir}|InvalidLast]}
+ end;
+ _ ->
+ %% this is a test run for a new test, not in cache
+ {[LogDir|NewAdded],
+ DeletedTests,ValidLast,InvalidLast}
+ end,
+ dir_diff_tests(LogDirs, CachedTests, New, DeletedTests1,
+ ValidLast1,InvalidLast1);
+
+dir_diff_tests([], _CachedTests, NewAdded, DeletedTests,
+ ValidLast, InvalidLast) ->
+ %% We have to check if LastLogDir still exists or if it's been
+ %% deleted. InvalidLast contains all log dirs that should be deleted,
+ %% if not present in ValidLast.
+ InvalidLast1 =
+ lists:foldl(fun(TDir,IL) ->
+ case lists:member(TDir,ValidLast) of
+ true ->
+ [TD || TD <- IL, TD /= TDir];
+ false ->
+ [TDir | [TD || TD <- IL, TD /= TDir]]
+ end
+ end, InvalidLast, InvalidLast),
+
+ %% Collect all tests for which LastLogDir has been deleted.
+ DeletedTests1 = [T || {T,_} <- InvalidLast1] ++ DeletedTests,
+
+ %% Make sure that directories for tests that are to be deleted are
+ %% saved in NewAdded so that tests don't disappear from the log if
+ %% older run dirs for them exist.
+ NewAdded1 = lists:map(fun({_TestName,RunDir}) ->
+ [TopDir,TestDir|_] = filename:split(RunDir),
+ filename:join(TopDir,TestDir)
+ end, InvalidLast1) ++ NewAdded,
+
+ {NewAdded1,DeletedTests1}.
+
+delete_tests_from_cache(OldTests, LogCache=#log_cache{tests=Tests}) ->
+ Tests2 = lists:foldl(fun(T,Tests1) ->
+ lists:keydelete(T,1,Tests1)
+ end, Tests, OldTests),
+ LogCache#log_cache{tests = Tests2}.
+
+update_tests_in_cache(TempData) ->
+ case get(ct_log_cache) of
+ undefined ->
+ update_tests_in_cache(TempData,#log_cache{version = cache_vsn(),
+ tests=[]});
+ SavedLogCache ->
+ update_tests_in_cache(TempData,binary_to_term(SavedLogCache))
+ end.
+
+update_tests_in_cache(TempData,LogCache=#log_cache{tests=Tests}) ->
+ Cached1 =
+ if Tests == [] ->
+ [];
+ true ->
+ lists:foldl(fun({TestName,_,_,_,_},Cached) ->
+ lists:keydelete(TestName,1,Cached)
+ end, Tests, TempData)
+ end,
+ Tests1 = lists:keysort(1,TempData++Cached1),
+ CacheBin = term_to_binary(LogCache#log_cache{tests = Tests1}),
+ case {self(),whereis(?MODULE)} of
+ {_Pid,_Pid} ->
+ put(ct_log_cache,CacheBin);
+ _ ->
+ file:write_file(?log_cache_name,CacheBin)
+ end.
+
+%%
+%% AllTestLogDirs =
+%% [{TestName,[IxDir|IxDirs]} | ...] (non-cached), or
+%% [{TestName,Label,Missing,{IxDir,Summary,URIs},IxDirs} | ...] (cached)
+%%
+make_all_suites_index1(When, AbsIndexName, AllTestLogDirs) ->
IndexName = ?index_name,
if When == start -> ok;
true -> io:put_chars("Updating " ++ AbsIndexName ++ "... ")
end,
- case catch make_all_suites_index2(IndexName, AllLogDirs) of
+ case catch make_all_suites_index2(IndexName, AllTestLogDirs) of
{'EXIT', Reason} ->
io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"),
io:format("~p~n", [Reason]),
@@ -1917,15 +2371,15 @@ make_all_suites_index1(When, AbsIndexName, AllLogDirs) ->
io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"),
io:format("~p~n", [Reason]),
{error, Reason};
- {ok,CacheData} ->
+ {ok,TempData} ->
case When of
start ->
ct_util:set_testdata_async({test_index,{AbsIndexName,
- CacheData}}),
- ok;
+ TempData}}),
+ TempData;
_ ->
io:put_chars("done\n"),
- ok
+ TempData
end;
Err ->
io:format("Unknown internal error while updating ~ts. "
@@ -1935,21 +2389,57 @@ make_all_suites_index1(When, AbsIndexName, AllLogDirs) ->
end.
make_all_suites_index2(IndexName, AllTestLogDirs) ->
- {ok,Index0,_Totals,CacheData} =
+ {ok,Index0,_Totals,TempData} =
make_all_suites_index3(AllTestLogDirs,
all_suites_index_header(),
0, 0, 0, 0, 0, [], []),
- Index = [Index0|index_footer()],
+ Index = [Index0|all_suites_index_footer()],
case force_write_file(IndexName, unicode:characters_to_binary(Index)) of
ok ->
- {ok,CacheData};
+ {ok,TempData};
{error, Reason} ->
{error,{index_write_error, Reason}}
end.
+%%
+%% AllTestLogDirs = [{TestName,Label,Missing,{LogDir,Summary,URIs},OldDirs}]
+%% Summary = {Succ,Fail,UserSkip,AutoSkip} | error
+%% URIs = {CtRunLogURI,LogFileURI,CrashDumpURI} | undefined
+%%
+%% this clause is for handling entries in the log cache
+make_all_suites_index3([IxEntry = {TestName,Label,Missing,
+ {LastLogDir,Summary,URIs},OldDirs} | Rest],
+ Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,
+ Labels, TempData) ->
+ [EntryDir|_] = filename:split(LastLogDir),
+ Labels1 = [{EntryDir,Label}|Labels],
+ case Summary of
+ {Succ,Fail,USkip,ASkip} ->
+ All = {true,OldDirs},
+ NotBuilt = not_built(TestName, LastLogDir, All, Missing),
+
+ {Result1,_} = make_one_index_entry1(TestName, LastLogDir, Label,
+ Succ, Fail, USkip, ASkip,
+ NotBuilt, All, temp, URIs),
+
+ AutoSkip1 = case catch AutoSkip+ASkip of
+ {'EXIT',_} -> undefined;
+ Res -> Res
+ end,
+ make_all_suites_index3(Rest, [Result|Result1], TotSucc+Succ,
+ TotFail+Fail, UserSkip+USkip, AutoSkip1,
+ TotNotBuilt+NotBuilt, Labels1,
+ [IxEntry|TempData]);
+ error ->
+ make_all_suites_index3(Rest, Result, TotSucc, TotFail,
+ UserSkip, AutoSkip, TotNotBuilt, Labels1,
+ [IxEntry|TempData])
+ end;
+
+%% this clause is for handling non-cached directories
make_all_suites_index3([{TestName,[LastLogDir|OldDirs]}|Rest],
Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,
- Labels, CacheData) ->
+ Labels, TempData) ->
[EntryDir|_] = filename:split(LastLogDir),
Missing =
case file:read_file(filename:join(EntryDir, ?missing_suites_info)) of
@@ -1966,38 +2456,50 @@ make_all_suites_index3([{TestName,[LastLogDir|OldDirs]}|Rest],
Lbl ->
{Lbl,Labels}
end,
- case make_one_index_entry(TestName, LastLogDir, Label, {true,OldDirs}, Missing) of
- {Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
+ case make_one_index_entry(TestName, LastLogDir, Label,
+ {true,OldDirs}, Missing, undefined) of
+ {Result1,Succ,Fail,USkip,ASkip,NotBuilt,URIs} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
{'EXIT',_} -> undefined;
Res -> Res
end,
IxEntry = {TestName,Label,Missing,
- {LastLogDir,{Succ,Fail,USkip,ASkip}},OldDirs},
+ {LastLogDir,{Succ,Fail,USkip,ASkip},URIs},OldDirs},
+
make_all_suites_index3(Rest, [Result|Result1], TotSucc+Succ,
TotFail+Fail, UserSkip+USkip, AutoSkip1,
TotNotBuilt+NotBuilt, Labels1,
- [IxEntry|CacheData]);
+ [IxEntry|TempData]);
error ->
- IxEntry = {TestName,Label,Missing,{LastLogDir,error},OldDirs},
+ IxEntry = {TestName,Label,Missing,
+ {LastLogDir,error,undefined},OldDirs},
make_all_suites_index3(Rest, Result, TotSucc, TotFail,
UserSkip, AutoSkip, TotNotBuilt, Labels1,
- [IxEntry|CacheData])
+ [IxEntry|TempData])
end;
+
+%% something wrong with this test dir, ignore
+make_all_suites_index3([_|Rest], Result, TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt, Labels, TempData) ->
+ make_all_suites_index3(Rest, Result, TotSucc, TotFail,
+ UserSkip, AutoSkip, TotNotBuilt, Labels,
+ TempData);
+
make_all_suites_index3([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
- TotNotBuilt, _, CacheData) ->
- {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,true)],
- {TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}, lists:reverse(CacheData)}.
+ TotNotBuilt, _, TempData) ->
+ {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt,true)],
+ {TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}, lists:reverse(TempData)}.
-make_all_suites_ix_cached(AbsIndexName, NewTestData, Label, AllTestLogDirs) ->
+make_all_suites_ix_temp(AbsIndexName, NewTestData, Label, AllTestLogDirs) ->
AllTestLogDirs1 = insert_new_test_data(NewTestData, Label, AllTestLogDirs),
IndexDir = filename:dirname(AbsIndexName),
- Index0 = make_all_suites_ix_cached1(AllTestLogDirs1,
- all_suites_index_header(IndexDir),
- 0, 0, 0, 0, 0),
- Index = [Index0|index_footer()],
+ Index0 = make_all_suites_ix_temp1(AllTestLogDirs1,
+ all_suites_index_header(IndexDir),
+ 0, 0, 0, 0, 0),
+ Index = [Index0|all_suites_index_footer()],
case force_write_file(AbsIndexName, unicode:characters_to_binary(Index)) of
ok ->
ok;
@@ -2008,51 +2510,94 @@ make_all_suites_ix_cached(AbsIndexName, NewTestData, Label, AllTestLogDirs) ->
insert_new_test_data({NewTestName,NewTestDir}, NewLabel, AllTestLogDirs) ->
AllTestLogDirs1 =
case lists:keysearch(NewTestName, 1, AllTestLogDirs) of
- {value,{_,_,_,{LastLogDir,_},OldDirs}} ->
- [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0}},
+ {value,{_,_,_,{LastLogDir,_,_},OldDirs}} ->
+ [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0},undefined},
[LastLogDir|OldDirs]} |
lists:keydelete(NewTestName, 1, AllTestLogDirs)];
false ->
- [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0}},[]} |
+ [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0},undefined},[]} |
AllTestLogDirs]
end,
lists:keysort(1, AllTestLogDirs1).
-make_all_suites_ix_cached1([{TestName,Label,Missing,LastLogDirData,OldDirs}|Rest],
- Result, TotSucc, TotFail, UserSkip, AutoSkip,
- TotNotBuilt) ->
-
- case make_one_ix_entry_cached(TestName, LastLogDirData,
- Label, {true,OldDirs}, Missing) of
- {Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
+make_all_suites_ix_temp1([{TestName,Label,Missing,LastLogDirData,OldDirs}|Rest],
+ Result, TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt) ->
+ case make_one_ix_entry_temp(TestName, LastLogDirData,
+ Label, {true,OldDirs}, Missing) of
+ {Result1,Succ,Fail,USkip,ASkip,NotBuilt,_URIs} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
{'EXIT',_} -> undefined;
Res -> Res
end,
- make_all_suites_ix_cached1(Rest, [Result|Result1], TotSucc+Succ,
- TotFail+Fail, UserSkip+USkip, AutoSkip1,
- TotNotBuilt+NotBuilt);
+ make_all_suites_ix_temp1(Rest, [Result|Result1], TotSucc+Succ,
+ TotFail+Fail, UserSkip+USkip, AutoSkip1,
+ TotNotBuilt+NotBuilt);
error ->
- make_all_suites_ix_cached1(Rest, Result, TotSucc, TotFail,
- UserSkip, AutoSkip, TotNotBuilt)
+ make_all_suites_ix_temp1(Rest, Result, TotSucc, TotFail,
+ UserSkip, AutoSkip, TotNotBuilt)
end;
-make_all_suites_ix_cached1([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
- TotNotBuilt) ->
+make_all_suites_ix_temp1([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt) ->
[Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, true)].
-make_one_ix_entry_cached(TestName, {LogDir,Summary}, Label, All, Missing) ->
+make_one_ix_entry_temp(TestName, {LogDir,Summary,URIs}, Label, All, Missing) ->
case Summary of
{Succ,Fail,UserSkip,AutoSkip} ->
NotBuilt = not_built(TestName, LogDir, All, Missing),
- NewResult = make_one_index_entry1(TestName, LogDir, Label,
- Succ, Fail, UserSkip, AutoSkip,
- NotBuilt, All, cached),
- {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt};
+ {NewResult,URIs1} = make_one_index_entry1(TestName, LogDir, Label,
+ Succ, Fail,
+ UserSkip, AutoSkip,
+ NotBuilt, All, temp, URIs),
+ {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt,URIs1};
error ->
error
end.
+%%%-----------------------------------------------------------------
+%%%
+get_cache_data({ok,CacheBin}) ->
+ case binary_to_term(CacheBin) of
+ CacheRec when is_record(CacheRec,log_cache) ->
+ %% make sure we don't use a cache on old format
+ case is_correct_cache_vsn(CacheRec) of
+ true ->
+ {ok,CacheRec};
+ false ->
+ file:delete(?log_cache_name),
+ {error,old_cache_file}
+ end;
+ _ ->
+ file:delete(?log_cache_name),
+ {error,invalid_cache_file}
+ end;
+get_cache_data(NoCache) ->
+ NoCache.
+
+cache_vsn() ->
+ application:load(common_test),
+ case application:get_key(common_test,vsn) of
+ {ok,VSN} ->
+ VSN;
+ _ ->
+ EbinDir = filename:dirname(code:which(ct)),
+ VSNfile = filename:join([EbinDir,"..","vsn.mk"]),
+ case file:read_file(VSNfile) of
+ {ok,Bin} ->
+ [_,VSN] = string:tokens(binary_to_list(Bin),[$=,$\n,$ ]),
+ VSN;
+ _ ->
+ undefined
+ end
+ end.
+
+is_correct_cache_vsn(#log_cache{version = CVSN}) ->
+ case cache_vsn() of
+ CVSN -> true;
+ _ -> false
+ end.
+
%%-----------------------------------------------------------------
%% Remove log files.
%% Cwd should always be set to the root logdir when finished.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 57cfab532e..41d53c7b43 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -329,6 +329,13 @@ script_start1(Parent, Args) ->
application:set_env(common_test, basic_html, true),
true
end,
+ %% disable_log_cache - used by ct_logs
+ case proplists:get_value(disable_log_cache, Args) of
+ undefined ->
+ application:set_env(common_test, disable_log_cache, false);
+ _ ->
+ application:set_env(common_test, disable_log_cache, true)
+ end,
Opts = #opts{label = Label, profile = Profile,
vts = Vts, shell = Shell,
@@ -1039,6 +1046,13 @@ run_test2(StartOpts) ->
BasicHtmlBool
end,
+ case proplists:get_value(disable_log_cache, StartOpts) of
+ undefined ->
+ application:set_env(common_test, disable_log_cache, false);
+ DisableCacheBool ->
+ application:set_env(common_test, disable_log_cache, DisableCacheBool)
+ end,
+
%% stepped execution
Step = get_start_opt(step, value, StartOpts),
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index beb3c1d649..4755d939e0 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -309,7 +309,7 @@ expect(Connection,Patterns) ->
%%% Tag = term()
%%% Opts = [Opt]
%%% Opt = {timeout,Timeout} | repeat | {repeat,N} | sequence |
-%%% {halt,HaltPatterns} | ignore_prompt
+%%% {halt,HaltPatterns} | ignore_prompt | no_prompt_check
%%% Timeout = integer()
%%% N = integer()
%%% HaltPatterns = Patterns
@@ -336,14 +336,28 @@ expect(Connection,Patterns) ->
%%% will also include the matched <code>Tag</code>. Else, only
%%% <code>RxMatch</code> is returned.</p>
%%%
-%%% <p>The function will always return when a prompt is found, unless
-%%% the <code>ignore_prompt</code> options is used.</p>
-%%%
%%% <p>The <code>timeout</code> option indicates that the function
%%% shall return if the telnet client is idle (i.e. if no data is
%%% received) for more than <code>Timeout</code> milliseconds. Default
%%% timeout is 10 seconds.</p>
%%%
+%%% <p>The function will always return when a prompt is found, unless
+%%% any of the <code>ignore_prompt</code> or
+%%% <code>no_prompt_check</code> options are used, in which case it
+%%% will return when a match is found or after a timeout.</p>
+%%%
+%%% <p>If the <code>ignore_prompt</code> option is used,
+%%% <code>ct_telnet</code> will ignore any prompt found. This option
+%%% is useful if data sent by the server could include a pattern that
+%%% would match the prompt regexp (as returned by
+%%% <code>TargedMod:get_prompt_regexp/0</code>), but which should not
+%%% cause the function to return.</p>
+%%%
+%%% <p>If the <code>no_prompt_check</code> option is used,
+%%% <code>ct_telnet</code> will not search for a prompt at all. This
+%%% is useful if, for instance, the <code>Pattern</code> itself
+%%% matches the prompt.</p>
+%%%
%%% <p>The <code>repeat</code> option indicates that the pattern(s)
%%% shall be matched multiple times. If <code>N</code> is given, the
%%% pattern(s) will be matched <code>N</code> times, and the function
@@ -729,7 +743,7 @@ teln_get_all_data(Pid,Prx,Data,Acc,LastLine) ->
seq=false,
repeat=false,
found_prompt=false,
- wait_for_linebreak=true}).
+ prompt_check=true}).
%% @hidden
%% @doc Externally the silent_teln_expect function shall only be used
@@ -755,25 +769,27 @@ silent_teln_expect(Pid,Data,Pattern,Prx,Opts) ->
%% condition is fullfilled.
%% 3b) Repeat (sequence): 2) is repeated either N times or until a
%% halt condition is fullfilled.
-teln_expect(Pid,Data,Pattern0,Prx,Opts) ->
- HaltPatterns = case get_ignore_prompt(Opts) of
- true ->
- get_haltpatterns(Opts);
- false ->
- [prompt | get_haltpatterns(Opts)]
- end,
- WaitForLineBreak = get_line_break_opt(Opts),
+teln_expect(Pid,Data,Pattern0,Prx,Opts) ->
+ HaltPatterns =
+ case get_ignore_prompt(Opts) of
+ true ->
+ get_haltpatterns(Opts);
+ false ->
+ [prompt | get_haltpatterns(Opts)]
+ end,
+
+ PromptCheck = get_prompt_check(Opts),
Seq = get_seq(Opts),
Pattern = convert_pattern(Pattern0,Seq),
-
+
Timeout = get_timeout(Opts),
-
+
EO = #eo{teln_pid=Pid,
prx=Prx,
timeout=Timeout,
seq=Seq,
haltpatterns=HaltPatterns,
- wait_for_linebreak=WaitForLineBreak},
+ prompt_check=PromptCheck},
case get_repeat(Opts) of
false ->
@@ -814,11 +830,6 @@ get_timeout(Opts) ->
{value,{timeout,T}} -> T;
false -> ?DEFAULT_TIMEOUT
end.
-get_line_break_opt(Opts) ->
- case lists:keysearch(wait_for_linebreak,1,Opts) of
- {value,{wait_for_linebreak,false}} -> false;
- _ -> true
- end.
get_repeat(Opts) ->
case lists:keysearch(repeat,1,Opts) of
{value,{repeat,N}} when is_integer(N) ->
@@ -842,7 +853,9 @@ get_haltpatterns(Opts) ->
end.
get_ignore_prompt(Opts) ->
lists:member(ignore_prompt,Opts).
-
+get_prompt_check(Opts) ->
+ not lists:member(no_prompt_check,Opts).
+
%% Repeat either single or sequence. All match results are accumulated
%% and returned when a halt condition is fulllfilled.
repeat_expect(Rest,_Pattern,Acc,#eo{repeat=0}) ->
@@ -903,6 +916,9 @@ get_data1(Pid) ->
%% lines and each line is matched against each pattern.
%% one_expect: split data chunk at prompts
+one_expect(Data,Pattern,EO) when EO#eo.prompt_check==false ->
+% io:format("Raw Data ~p Pattern ~p EO ~p ",[Data,Pattern,EO]),
+ one_expect1(Data,Pattern,[],EO#eo{found_prompt=false});
one_expect(Data,Pattern,EO) ->
case match_prompt(Data,EO#eo.prx) of
{prompt,UptoPrompt,PromptType,Rest} ->
@@ -961,6 +977,8 @@ seq_expect(Data,[],Acc,_EO) ->
{match,lists:reverse(Acc),Data};
seq_expect([],Patterns,Acc,_EO) ->
{continue,Patterns,lists:reverse(Acc),[]};
+seq_expect(Data,Patterns,Acc,EO) when EO#eo.prompt_check==false ->
+ seq_expect1(Data,Patterns,Acc,[],EO#eo{found_prompt=false});
seq_expect(Data,Patterns,Acc,EO) ->
case match_prompt(Data,EO#eo.prx) of
{prompt,UptoPrompt,PromptType,Rest} ->
@@ -1015,9 +1033,8 @@ seq_expect1(Data,[],Acc,Rest,_EO) ->
%% Split prompt-chunk at lines
match_lines(Data,Patterns,EO) ->
FoundPrompt = EO#eo.found_prompt,
- NeedLineBreak = EO#eo.wait_for_linebreak,
case one_line(Data,[]) of
- {noline,Rest} when FoundPrompt=/=false, NeedLineBreak =:= true ->
+ {noline,Rest} when FoundPrompt=/=false ->
%% This is the line including the prompt
case match_line(Rest,Patterns,FoundPrompt,EO) of
nomatch ->
@@ -1025,14 +1042,14 @@ match_lines(Data,Patterns,EO) ->
{Tag,Match} ->
{Tag,Match,[]}
end;
- {noline,Rest} when NeedLineBreak =:= false ->
- case match_line(Rest,Patterns,FoundPrompt,EO) of
+ {noline,Rest} when EO#eo.prompt_check==false ->
+ case match_line(Rest,Patterns,false,EO) of
nomatch ->
- {nomatch,prompt};
+ {nomatch,Rest};
{Tag,Match} ->
{Tag,Match,[]}
end;
- {noline, Rest} ->
+ {noline,Rest} ->
{nomatch,Rest};
{Line,Rest} ->
case match_line(Line,Patterns,false,EO) of
diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl
index 7329498ed6..2cbcba9c77 100644
--- a/lib/common_test/src/ct_telnet_client.erl
+++ b/lib/common_test/src/ct_telnet_client.erl
@@ -143,7 +143,9 @@ loop(State, Sock, Acc) ->
State
end;
_ ->
- Pid ! {data,lists:reverse(lists:append(Acc))},
+ Data = lists:reverse(lists:append(Acc)),
+ dbg("get_data ~p\n",[Data]),
+ Pid ! {data,Data},
State
end,
loop(NewState, Sock, []);
@@ -161,7 +163,9 @@ loop(State, Sock, Acc) ->
NewAcc =
case erlang:is_process_alive(Pid) of
true ->
- Pid ! {data,lists:reverse(lists:append(Acc))},
+ Data = lists:reverse(lists:append(Acc)),
+ dbg("get_data_delayed ~p\n",[Data]),
+ Pid ! {data,Data},
[];
false ->
Acc
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 02e58d0786..b77845eb5b 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -414,11 +414,15 @@ loop(Mode,TestData,StartDir) ->
[#conn{address=A,callback=CB}] ->
%% A connection crashed - remove the connection but don't die
ct_logs:tc_log_async(ct_error_notify,
+ ?MAX_IMPORTANCE,
+ "CT Error Notification",
"Connection process died: "
"Pid: ~w, Address: ~p, Callback: ~w\n"
"Reason: ~p\n\n",
[Pid,A,CB,Reason]),
catch CB:close(Pid),
+ %% in case CB:close failed to do this:
+ unregister_connection(Pid),
loop(Mode,TestData,StartDir);
_ ->
%% Let process crash in case of error, this shouldn't happen!
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 78ae70f37e..958b7a94c7 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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
@@ -33,6 +33,8 @@
handle_event/2, handle_call/2, handle_info/2,
terminate/1]).
+-include("ct.hrl").
+
id(_Opts) ->
?MODULE.
@@ -78,7 +80,7 @@ handle_event(Event, LogFunc) ->
SReport = sasl_report:format_report(group_leader(), ErrLogType,
tag_event(Event)),
if is_list(SReport) ->
- ct_logs:LogFunc(sasl, SReport, []);
+ ct_logs:LogFunc(sasl, ?STD_IMPORTANCE, "System", SReport, []);
true -> %% Report is an atom if no logging is to be done
ignore
end
@@ -86,7 +88,7 @@ handle_event(Event, LogFunc) ->
EReport = error_logger_tty_h:write_event(
tag_event(Event),io_lib),
if is_list(EReport) ->
- ct_logs:LogFunc(error_logger, EReport, []);
+ ct_logs:LogFunc(error_logger, ?STD_IMPORTANCE, "System", EReport, []);
true -> %% Report is an atom if no logging is to be done
ignore
end,
diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl
index 71df2ab44e..88199b07d0 100644
--- a/lib/common_test/src/unix_telnet.erl
+++ b/lib/common_test/src/unix_telnet.erl
@@ -94,16 +94,11 @@ connect(Ip,Port,Timeout,KeepAlive,Extra) ->
{Username,Password} ->
connect1(Ip,Port,Timeout,KeepAlive,Username,Password);
Name ->
- 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
+ case get_username_and_password(Name) of
+ {ok,{Username,Password}} ->
+ connect1(Ip,Port,Timeout,KeepAlive,Username,Password);
+ Error ->
+ Error
end
end.
@@ -149,27 +144,6 @@ 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 94569fa87f..31ab28c41d 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -28,6 +28,7 @@ MODULES= \
ct_test_support \
ct_test_support_eh \
ct_userconfig_callback \
+ telnet_server \
ct_smoke_test_SUITE \
ct_priv_dir_SUITE \
ct_event_handler_SUITE \
diff --git a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
index d967590c72..83d368c53d 100644
--- a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
+++ b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
@@ -52,11 +52,10 @@ init_per_testcase(_Case, Config) ->
[{watchdog, Dog}|Config].
end_per_testcase(Case, Config) ->
- %% try apply(?MODULE,Case,[cleanup,Config])
- %% catch error:undef -> ok
- %% end,
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
- kill_slaves(Case,nodes()),
Dog=?config(watchdog, Config),
test_server:timetrap_cancel(Dog),
ok.
@@ -67,12 +66,12 @@ break(_Config) ->
test_server:break(""),
ok.
-default(Config) ->
+default(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
ok.
-slave(Config) ->
+slave(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
N1 = nodename(slave,1),
@@ -81,8 +80,10 @@ slave(Config) ->
rpc:call(Node,cover_test_mod,foo,[]),
{ok,Node} = ct_slave:stop(N1),
ok.
+slave(cleanup,_Config) ->
+ kill_slaves([nodename(slave,1)]).
-slave_start_slave(Config) ->
+slave_start_slave(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
N1 = nodename(slave_start_slave,1),
@@ -90,13 +91,16 @@ slave_start_slave(Config) ->
{ok,Node} = start_slave(N1),
cover_compiled = rpc:call(Node,code,which,[cover_test_mod]),
rpc:call(Node,cover_test_mod,foo,[]),
- {ok,Node2} = rpc:call(Node,ct_slave,start,[N2]),
+ {ok,Node2} = start_slave(Node,N2), % start slave N2 from node Node
rpc:call(Node2,cover_test_mod,foo,[]),
{ok,Node2} = rpc:call(Node,ct_slave,stop,[N2]),
{ok,Node} = ct_slave:stop(N1),
ok.
+slave_start_slave(cleanup,_Config) ->
+ kill_slaves([nodename(slave_start_slave,1),
+ nodename(slave_start_slave,2)]).
-cover_node_option(Config) ->
+cover_node_option(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
Node = fullname(existing_node_1),
@@ -104,7 +108,7 @@ cover_node_option(Config) ->
rpc:call(Node,cover_test_mod,foo,[]),
ok.
-ct_cover_add_remove_nodes(Config) ->
+ct_cover_add_remove_nodes(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
Node = fullname(existing_node_2),
@@ -143,22 +147,20 @@ fullname(Name) ->
{ok,Host} = inet:gethostname(),
list_to_atom(atom_to_list(Name) ++ "@" ++ Host).
-kill_slaves(Case, [Node|Nodes]) ->
- Prefix = nodeprefix(Case),
- case lists:prefix(Prefix,atom_to_list(Node)) of
- true ->
- rpc:call(Node,erlang,halt,[]);
- _ ->
- ok
- end,
- kill_slaves(Case,Nodes);
-kill_slaves(_,[]) ->
+kill_slaves([Name|Names]) ->
+ _ = rpc:call(fullname(Name),erlang,halt,[]),
+ kill_slaves(Names);
+kill_slaves([]) ->
ok.
start_slave(Name) ->
+ start_slave(node(),Name).
+
+start_slave(FromNode,Name) ->
{ok, HostStr}=inet:gethostname(),
Host = list_to_atom(HostStr),
- ct_slave:start(Host,Name,
- [{boot_timeout,10}, % extending some timers for slow test hosts
- {init_timeout,10},
- {startup_timeout,10}]).
+ rpc:call(FromNode,ct_slave,start,
+ [Host,Name,
+ [{boot_timeout,15}, % extending some timers for slow test hosts
+ {init_timeout,15},
+ {startup_timeout,15}]]).
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
index 54526e8e83..0535eb924b 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% 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
@@ -1035,10 +1035,12 @@ make_dsa_files(Config, Type) ->
file:write_file(DSAPrivateFile, PemBin),
ok.
+
%%--------------------------------------------------------------------
-%% Creates a dsa key (OBS: for testing only)
+%% @doc Creates a dsa key (OBS: for testing only)
%% the sizes are in bytes
-%% gen_dsa(::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
%%--------------------------------------------------------------------
gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
Key = gen_dsa2(LSize, NSize),
@@ -1048,7 +1050,6 @@ encode_key(Key = #'DSAPrivateKey'{}) ->
Der = public_key:der_encode('DSAPrivateKey', Key),
{'DSAPrivateKey', Der, not_encrypted}.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% DSA key generation (OBS: for testing only)
%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm
@@ -1058,67 +1059,70 @@ gen_dsa2(LSize, NSize) ->
Q = prime(NSize), %% Choose N-bit prime Q
X0 = prime(LSize),
P0 = prime((LSize div 2) +1),
-
+
%% Choose L-bit prime modulus P such that p-1 is a multiple of q.
case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
- error ->
+ error ->
gen_dsa2(LSize, NSize);
- P ->
- G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ P ->
+ G = crypto:mod_pow(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
%% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
-
+
X = prime(20), %% Choose x by some random method, where 0 < x < q.
- Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
-
- #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ Y = crypto:mod_pow(G, X, P), %% Calculate y = g^x mod p.
+
+ #'DSAPrivateKey'{version=0, p = P, q = Q,
+ g = crypto:bytes_to_integer(G), y = crypto:bytes_to_integer(Y), x = X}
end.
-
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
- case is_prime(crypto:mpint(P), 50) of
+ case is_prime(P, 50) of
true -> P;
false -> dsa_search(T+1, P0, Q, Iter-1)
end;
-dsa_search(_,_,_,_) ->
+dsa_search(_,_,_,_) ->
error.
%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime(ByteSize) ->
Rand = odd_rand(ByteSize),
- crypto:erlint(prime_odd(Rand, 0)).
+ prime_odd(Rand, 0).
prime_odd(Rand, N) ->
case is_prime(Rand, 50) of
- true ->
+ true ->
Rand;
- false ->
- NotPrime = crypto:erlint(Rand),
- prime_odd(crypto:mpint(NotPrime+2), N+1)
+ false ->
+ prime_odd(Rand+2, N+1)
end.
%% see http://en.wikipedia.org/wiki/Fermat_primality_test
is_prime(_, 0) -> true;
-is_prime(Candidate, Test) ->
- CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
- case crypto:mod_exp(CoPrime, Candidate, Candidate) of
- CoPrime -> is_prime(Candidate, Test-1);
- _ -> false
- end.
+is_prime(Candidate, Test) ->
+ CoPrime = odd_rand(10000, Candidate),
+ Result = crypto:mod_pow(CoPrime, Candidate, Candidate) ,
+ is_prime(CoPrime, crypto:bytes_to_integer(Result), Candidate, Test).
+
+is_prime(CoPrime, CoPrime, Candidate, Test) ->
+ is_prime(Candidate, Test-1);
+is_prime(_,_,_,_) ->
+ false.
odd_rand(Size) ->
Min = 1 bsl (Size*8-1),
Max = (1 bsl (Size*8))-1,
- odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+ odd_rand(Min, Max).
odd_rand(Min,Max) ->
- Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
- BitSkip = (Sz+4)*8-1,
- case Rand of
- Odd = <<_:BitSkip, 1:1>> -> Odd;
- Even = <<_:BitSkip, 0:1>> ->
- crypto:mpint(crypto:erlint(Even)+1)
+ Rand = crypto:rand_uniform(Min,Max),
+ case Rand rem 2 of
+ 0 ->
+ Rand + 1;
+ _ ->
+ Rand
end.
copyfile(SrcDir, DstDir, Fn) ->
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
index 7ec384c932..35d67a10f2 100644
--- a/lib/common_test/test/ct_repeat_testrun_SUITE.erl
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
@@ -51,8 +51,8 @@
%% least 20 seconds (10 sec for each r1_SUITE:tc1)
%%
-define(t1,30). % time shall expire during second run of r1_SUITE
--define(t2,6). % time shall expire during first run of tc1
--define(t3,16). % time shall expire during second run of tc1
+-define(t2,9). % time shall expire during first run of tc1
+-define(t3,19). % time shall expire during second run of tc1
%%--------------------------------------------------------------------
diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl
index b4f24baa0c..e2ee207754 100644
--- a/lib/common_test/test/ct_telnet_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE.erl
@@ -33,6 +33,10 @@
-define(eh, ct_test_support_eh).
+-define(erl_telnet_server_port,1234).
+-define(erl_telnet_server_user,"telnuser").
+-define(erl_telnet_server_pwd,"telnpwd").
+
%%--------------------------------------------------------------------
%% TEST SERVER CALLBACK FUNCTIONS
%%--------------------------------------------------------------------
@@ -48,17 +52,28 @@ init_per_suite(Config) ->
end_per_suite(Config) ->
ct_test_support:end_per_suite(Config).
+init_per_testcase(TestCase, Config) when TestCase=/=unix_telnet->
+ TS = telnet_server:start([{port,?erl_telnet_server_port},
+ {users,[{?erl_telnet_server_user,
+ ?erl_telnet_server_pwd}]}]),
+ ct_test_support:init_per_testcase(TestCase, [{telnet_server,TS}|Config]);
init_per_testcase(TestCase, Config) ->
ct_test_support:init_per_testcase(TestCase, Config).
end_per_testcase(TestCase, Config) ->
+ case ?config(telnet_server,Config) of
+ undefined -> ok;
+ TS -> telnet_server:stop(TS)
+ end,
ct_test_support:end_per_testcase(TestCase, Config).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[
- default
+ unix_telnet,
+ own_server,
+ timetrap
].
%%--------------------------------------------------------------------
@@ -67,19 +82,33 @@ all() ->
%%%-----------------------------------------------------------------
%%%
-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).
+unix_telnet(Config) when is_list(Config) ->
+ all_tests_in_suite(unix_telnet,"ct_telnet_basic_SUITE","telnet.cfg",Config).
+
+own_server(Config) ->
+ all_tests_in_suite(own_server,"ct_telnet_own_server_SUITE",
+ "telnet2.cfg",Config).
+
+timetrap(Config) ->
+ all_tests_in_suite(timetrap,"ct_telnet_timetrap_SUITE",
+ "telnet3.cfg",Config).
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
+all_tests_in_suite(TestCase, SuiteName, CfgFileName, Config) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join(DataDir, SuiteName),
+ CfgFile = filename:join(DataDir, CfgFileName),
+ Cfg = telnet_config(TestCase),
+ ok = file:write_file(CfgFile, io_lib:write(Cfg) ++ "."),
+ {Opts,ERPid} = setup([{suite,Suite},
+ {label,TestCase},
+ {config,CfgFile}],
+ Config),
+ ok = execute(TestCase, Opts, ERPid, Config).
+
setup(Test, Config) ->
Opts0 = ct_test_support:get_opts(Config),
Level = ?config(trace_level, Config),
@@ -103,19 +132,40 @@ execute(Name, Opts, ERPid, Config) ->
reformat(Events, EH) ->
ct_test_support:reformat(Events, EH).
+
+telnet_config(unix_telnet) ->
+ {unix, ct:get_config(unix)};
+telnet_config(_) ->
+ {unix,[{telnet,"localhost"},
+ {port, ?erl_telnet_server_port},
+ {username,?erl_telnet_server_user},
+ {password,?erl_telnet_server_pwd},
+ {keep_alive,true}]}.
+
%%%-----------------------------------------------------------------
%%% TEST EVENTS
%%%-----------------------------------------------------------------
-events_to_check(default,Config) ->
+events_to_check(unix_telnet,Config) ->
+ all_cases(ct_telnet_basic_SUITE,Config);
+events_to_check(own_server,Config) ->
+ all_cases(ct_telnet_own_server_SUITE,Config);
+events_to_check(timetrap,_Config) ->
+ [{?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,tc_done,{ct_telnet_timetrap_SUITE,expect_timetrap,
+ {failed,{timetrap_timeout,7000}}}},
+ {?eh,tc_done,{ct_telnet_timetrap_SUITE,expect_success,ok}},
+ {?eh,stop_logging,[]}].
+
+all_cases(Suite,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),
+ Suite)),
+ TCs = Suite:all(),
+ code:purge(Suite),
+ code:delete(Suite),
OneTest =
[{?eh,start_logging,{'DEF','RUNDIR'}}] ++
- [{?eh,tc_done,{ct_telnet_basic_SUITE,TC,ok}} || TC <- TCs] ++
+ [{?eh,tc_done,{Suite,TC,ok}} || TC <- TCs] ++
[{?eh,stop_logging,[]}],
%% 2 tests (ct:run_test + script_start) is default
diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
new file mode 100644
index 0000000000..3f7c0d68bf
--- /dev/null
+++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
@@ -0,0 +1,184 @@
+-module(ct_telnet_own_server_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,erl_telnet_server,{unix,[telnet]}}].
+
+all() ->
+ [expect,
+ expect_repeat,
+ expect_sequence,
+ expect_error_prompt,
+ expect_error_timeout,
+ no_prompt_check,
+ no_prompt_check_repeat,
+ no_prompt_check_sequence,
+ no_prompt_check_timeout,
+ ignore_prompt,
+ ignore_prompt_repeat,
+ ignore_prompt_sequence,
+ ignore_prompt_timeout].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%% Simple expect
+expect(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo ayt"),
+ {ok,["ayt"]} = ct_telnet:expect(Handle, ["ayt"]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Expect with repeat option
+expect_repeat(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml xy xy"),
+ {ok,[["xy"],["xy"]],done} = ct_telnet:expect(Handle, ["xy"],[{repeat,2}]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Expect with sequence option
+expect_sequence(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml ab cd ef"),
+ {ok,[["ab"],["cd"],["ef"]]} = ct_telnet:expect(Handle,
+ [["ab"],["cd"],["ef"]],
+ [sequence]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Check that expect returns when a prompt is found, even if pattern
+%% is not matched.
+expect_error_prompt(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx> yyy"),
+ {error,{prompt,"> "}} = ct_telnet:expect(Handle, ["yyy"]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Check that expect returns after idle timeout, and even if the
+%% expected pattern is received - as long as not newline or prompt is
+%% received it will not match.
+expect_error_timeout(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_no_prompt xxx"),
+ {error,timeout} = ct_telnet:expect(Handle, ["xxx"], [{timeout,1000}]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% expect with ignore_prompt option should not return even if a prompt
+%% is found. The pattern after the prompt (here "> ") can be matched.
+ignore_prompt(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx> yyy"),
+ {ok,["yyy"]} = ct_telnet:expect(Handle, ["yyy"], [ignore_prompt]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% expect with ignore_prompt and repeat options.
+ignore_prompt_repeat(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml yyy> yyy>"),
+ {ok,[["yyy"],["yyy"]],done} = ct_telnet:expect(Handle, ["yyy"],
+ [{repeat,2},
+ ignore_prompt]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% expect with ignore_prompt and sequence options.
+ignore_prompt_sequence(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml xxx> yyy> zzz> "),
+ {ok,[["xxx"],["yyy"],["zzz"]]} = ct_telnet:expect(Handle,
+ [["xxx"],["yyy"],["zzz"]],
+ [sequence,
+ ignore_prompt]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Check that expect returns after idle timeout when ignore_prompt
+%% option is used.
+%% As for expect without the ignore_prompt option, it a newline or a
+%% prompt is required in order for the pattern to match.
+ignore_prompt_timeout(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx"),
+ {error,timeout} = ct_telnet:expect(Handle, ["yyy"], [ignore_prompt,
+ {timeout,1000}]),
+ ok = ct_telnet:send(Handle, "echo xxx"), % sends prompt and newline
+ {ok,["xxx"]} = ct_telnet:expect(Handle, ["xxx"], [ignore_prompt,
+ {timeout,1000}]),
+ ok = ct_telnet:send(Handle, "echo_no_prompt xxx\n"), % no prompt, but newline
+ {ok,["xxx"]} = ct_telnet:expect(Handle, ["xxx"], [ignore_prompt,
+ {timeout,1000}]),
+ ok = ct_telnet:send(Handle, "echo_no_prompt xxx"), % no prompt, no newline
+ {error,timeout} = ct_telnet:expect(Handle, ["xxx"], [ignore_prompt,
+ {timeout,1000}]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% no_prompt_check option shall match pattern both when prompt is sent
+%% and when it is not.
+no_prompt_check(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx"),
+ {ok,["xxx"]} = ct_telnet:expect(Handle, ["xxx"], [no_prompt_check]),
+ ok = ct_telnet:send(Handle, "echo_no_prompt yyy"),
+ {ok,["yyy"]} = ct_telnet:expect(Handle, ["yyy"], [no_prompt_check]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% no_prompt_check and repeat options
+no_prompt_check_repeat(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml xxx xxx"),
+ {ok,[["xxx"],["xxx"]],done} = ct_telnet:expect(Handle,["xxx"],
+ [{repeat,2},
+ no_prompt_check]),
+ ok = ct_telnet:send(Handle, "echo_ml_no_prompt yyy yyy"),
+ {ok,[["yyy"],["yyy"]],done} = ct_telnet:expect(Handle,["yyy"],
+ [{repeat,2},
+ no_prompt_check]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% no_prompt_check and sequence options
+no_prompt_check_sequence(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml_no_prompt ab cd ef"),
+ {ok,[["ab"],["cd"],["ef"]]} = ct_telnet:expect(Handle,
+ [["ab"],["cd"],["ef"]],
+ [sequence,
+ no_prompt_check]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Check that expect returns after idle timeout when no_prompt_check
+%% option is used.
+no_prompt_check_timeout(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx"),
+ {error,timeout} = ct_telnet:expect(Handle, ["yyy"], [no_prompt_check,
+ {timeout,1000}]),
+ ok = ct_telnet:close(Handle),
+ ok.
diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_timetrap_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_timetrap_SUITE.erl
new file mode 100644
index 0000000000..f274fb9112
--- /dev/null
+++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_timetrap_SUITE.erl
@@ -0,0 +1,76 @@
+-module(ct_telnet_timetrap_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(name,erl_telnet_server).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+suite() -> [{require,?name,{unix,[telnet]}},
+ {timetrap,{seconds,7}}].
+
+all() ->
+ [expect_timetrap,
+ expect_success].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(_,Config) ->
+ ct:log("init_per_testcase: opening telnet connection...",[]),
+ {ok,_} = ct_telnet:open(?name),
+ ct:log("...done",[]),
+ Config.
+
+end_per_testcase(_,_Config) ->
+ ct:log("end_per_testcase: closing telnet connection...",[]),
+ _ = ct_telnet:close(?name),
+ ct:log("...done",[]),
+ ok.
+
+
+%% OTP-10648
+%% This test case should fail with timetrap timeout.
+%%
+%% The long timetrap timeout and timeout option in the expect call
+%% also causes the telnet client to hang so long that the attempt at
+%% closing it (in end_per_testcase) will time out (close timeout is 5
+%% sec) without a timetrap timeout occuring in end_per_testcase.
+%%
+%% The point is to see that the connection is thoroughly removed and
+%% unregistered anyway so that the next test case can successfully
+%% open a connection with the same name.
+%%
+%% Note!!! that if end_per_testcase reaches a timetrap timeout before
+%% the connection is closed, then the connection will survive until
+%% the hanging expect times out, after which it will be closed in a
+%% seemingly normal way due to the close message which was sent by the
+%% close attempt. This could happen any time during the subsequent
+%% test cases and cause confusion... There is however not much to do
+%% about this, except writing test cases with timetrap timeout longer
+%% than the close timeout (as this test case does)
+expect_timetrap(_) ->
+ {error,timeout} = ct_telnet:expect(?name, ["ayt"], [{timeout,20000}]),
+ ok.
+
+%% This should succeed
+expect_success(_) ->
+ ok = ct_telnet:send(?name, "echo ayt"),
+ {ok,["ayt"]} = ct_telnet:expect(?name, ["ayt"]),
+ ok.
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 70dd087358..6bcac12326 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -224,11 +224,38 @@ get_opts(Config) ->
%%%-----------------------------------------------------------------
%%%
-run(Opts, Config) when is_list(Opts) ->
+run(Opts0, Config) when is_list(Opts0) ->
+ Opts =
+ %% read (and override) opts from env variable, the form expected:
+ %% "[{some_key1,SomeVal2}, {some_key2,SomeVal2}]"
+ case os:getenv("CT_TEST_OPTS") of
+ false -> Opts0;
+ "" -> Opts0;
+ Terms ->
+ case erl_scan:string(Terms++".", 0) of
+ {ok,Tokens,_} ->
+ case erl_parse:parse_term(Tokens) of
+ {ok,OROpts} ->
+ Override =
+ fun(O={Key,_}, Os) ->
+ io:format(user, "ADDING START "
+ "OPTION: ~p~n", [O]),
+ [O | lists:keydelete(Key, 1, Os)]
+ end,
+ lists:foldl(Override, Opts0, OROpts);
+ _ ->
+ Opts0
+ end;
+ _ ->
+ Opts0
+ end
+ end,
+
%% use ct interface
CtRunTestResult=run_ct_run_test(Opts,Config),
%% use run_test interface (simulated)
ExitStatus=run_ct_script_start(Opts,Config),
+
check_result(CtRunTestResult,ExitStatus,Opts).
run_ct_run_test(Opts,Config) ->
@@ -236,9 +263,10 @@ run_ct_run_test(Opts,Config) ->
Level = proplists:get_value(trace_level, Config),
test_server:format(Level, "~n[RUN #1] Calling ct:run_test(~p) on ~p~n",
[Opts, CTNode]),
+ T0 = now(),
CtRunTestResult = rpc:call(CTNode, ct, run_test, [Opts]),
- test_server:format(Level, "~n[RUN #1] Got return value ~p~n",
- [CtRunTestResult]),
+ test_server:format(Level, "~n[RUN #1] Got return value ~p after ~p ms~n",
+ [CtRunTestResult,trunc(timer:now_diff(now(), T0)/1000)]),
case rpc:call(CTNode, erlang, whereis, [ct_util_server]) of
undefined ->
ok;
@@ -261,9 +289,10 @@ run_ct_script_start(Opts, Config) ->
[common_test, run_test_start_opts, Opts1]),
test_server:format(Level, "[RUN #2] Calling ct_run:script_start() on ~p~n",
[CTNode]),
+ T0 = now(),
ExitStatus = rpc:call(CTNode, ct_run, script_start, []),
- test_server:format(Level, "[RUN #2] Got exit status value ~p~n",
- [ExitStatus]),
+ test_server:format(Level, "[RUN #2] Got exit status value ~p after ~p ms~n",
+ [ExitStatus,trunc(timer:now_diff(now(), T0)/1000)]),
ExitStatus.
check_result({_Ok,Failed,{_UserSkipped,_AutoSkipped}},1,_Opts)
diff --git a/lib/common_test/test/telnet_server.erl b/lib/common_test/test/telnet_server.erl
new file mode 100644
index 0000000000..31884aa182
--- /dev/null
+++ b/lib/common_test/test/telnet_server.erl
@@ -0,0 +1,228 @@
+-module(telnet_server).
+-compile(export_all).
+
+%% telnet control characters
+-define(SE, 240).
+-define(NOP, 241).
+-define(DM, 242).
+-define(BRK, 243).
+-define(IP, 244).
+-define(AO, 245).
+-define(AYT, 246).
+-define(EC, 247).
+-define(EL, 248).
+-define(GA, 249).
+-define(SB, 250).
+-define(WILL, 251).
+-define(WONT, 252).
+-define(DO, 253).
+-define(DONT, 254).
+-define(IAC, 255).
+
+%% telnet options
+-define(BINARY, 0).
+-define(ECHO, 1).
+-define(SUPPRESS_GO_AHEAD, 3).
+-define(TERMINAL_TYPE, 24).
+
+-record(state,
+ {listen,
+ client,
+ users,
+ authorized=false,
+ suppress_go_ahead=false,
+ buffer=[]}).
+
+-type options() :: [{port,pos_integer()} | {users,users()}].
+-type users() :: [{user(),password()}].
+-type user() :: string().
+-type password() :: string().
+
+-spec start(Opts::options()) -> Pid::pid().
+start(Opts) when is_list(Opts) ->
+ spawn_link(fun() -> init(Opts) end).
+
+-spec stop(Pid::pid()) -> ok.
+stop(Pid) ->
+ Ref = erlang:monitor(process,Pid),
+ Pid ! stop,
+ receive {'DOWN',Ref,_,_,_} -> ok end.
+
+init(Opts) ->
+ Port = proplists:get_value(port,Opts),
+ Users = proplists:get_value(users,Opts,[]),
+ {ok, LSock} = gen_tcp:listen(Port, [list, {packet, 0},
+ {active, true}]),
+ State = #state{listen=LSock,users=Users},
+ accept(State),
+ ok = gen_tcp:close(LSock).
+
+accept(#state{listen=LSock}=State) ->
+ Server = self(),
+ Acceptor = spawn_link(fun() -> do_accept(LSock,Server) end),
+ receive
+ {Acceptor,Sock} when is_port(Sock) ->
+ case init_client(State#state{client=Sock}) of
+ stopped ->
+ io:format("telnet_server stopped\n"),
+ ok;
+ R ->
+ io:format("connection to client closed with reason ~p~n",[R]),
+ accept(State)
+ end;
+ {Acceptor,closed} ->
+ io:format("listen socket closed unexpectedly, "
+ "terminating telnet_server\n"),
+ ok;
+ stop ->
+ io:format("telnet_server stopped\n"),
+ ok
+ end.
+
+do_accept(LSock,Server) ->
+ case gen_tcp:accept(LSock) of
+ {ok, Sock} ->
+ ok = gen_tcp:controlling_process(Sock,Server),
+ Server ! {self(),Sock};
+ {error,closed} ->
+ %% This will happen when stop/1 is called, since listen
+ %% socket is closed. Then the server is probably already
+ %% dead by now, but to be 100% sure not to hang, we send a
+ %% message to say what happened.
+ Server ! {self(),closed}
+ end.
+
+init_client(#state{client=Sock}=State) ->
+ dbg("Server sending: ~p~n",["login: "]),
+ R = case gen_tcp:send(Sock,"login: ") of
+ ok ->
+ loop(State);
+ Error ->
+ Error
+ end,
+ _ = gen_tcp:close(Sock),
+ R.
+
+loop(State) ->
+ receive
+ {tcp,_,Data} ->
+ try handle_data(Data,State) of
+ {ok,State1} ->
+ loop(State1)
+ catch
+ throw:Error ->
+ Error
+ end;
+ {tcp_closed, _} ->
+ closed;
+ {tcp_error,_,Error} ->
+ {error,tcp,Error};
+ stop ->
+ stopped
+ end.
+
+handle_data([?IAC|Cmd],State) ->
+ dbg("Server got cmd: ~p~n",[Cmd]),
+ handle_cmd(Cmd,State);
+handle_data(Data,State) ->
+ dbg("Server got data: ~p~n",[Data]),
+ case get_line(Data,[]) of
+ {Line,Rest} ->
+ WholeLine = lists:flatten(lists:reverse(State#state.buffer,Line)),
+ {ok,State1} = do_handle_data(WholeLine,State),
+ case Rest of
+ [] -> {ok,State1};
+ _ -> handle_data(Rest,State1)
+ end;
+ false ->
+ {ok,State#state{buffer=[Data|State#state.buffer]}}
+ end.
+
+%% Add function clause below to handle new telnet commands (sent with
+%% ?IAC from client - this is not possible to do from ct_telnet API,
+%% but ct_telnet sends DONT SUPPRESS_GO_AHEAD)
+handle_cmd([?DO,?SUPPRESS_GO_AHEAD|T],State) ->
+ send([?IAC,?WILL,?SUPPRESS_GO_AHEAD],State),
+ handle_cmd(T,State#state{suppress_go_ahead=true});
+handle_cmd([?DONT,?SUPPRESS_GO_AHEAD|T],State) ->
+ send([?IAC,?WONT,?SUPPRESS_GO_AHEAD],State),
+ handle_cmd(T,State#state{suppress_go_ahead=false});
+handle_cmd([?IAC|T],State) ->
+ %% Multiple commands in one packet
+ handle_cmd(T,State);
+handle_cmd([_H|T],State) ->
+ %% Not responding to this command
+ handle_cmd(T,State);
+handle_cmd([],State) ->
+ {ok,State}.
+
+%% Add function clause below to handle new text command (text entered
+%% from the telnet prompt)
+do_handle_data(Data,#state{authorized=false}=State) ->
+ check_user(Data,State);
+do_handle_data(Data,#state{authorized={user,_}}=State) ->
+ check_pwd(Data,State);
+do_handle_data("echo "++ Data,State) ->
+ send(Data++"\r\n> ",State),
+ {ok,State};
+do_handle_data("echo_no_prompt "++ Data,State) ->
+ send(Data,State),
+ {ok,State};
+do_handle_data("echo_ml "++ Data,State) ->
+ Lines = string:tokens(Data," "),
+ ReturnData = string:join(Lines,"\n"),
+ send(ReturnData++"\r\n> ",State),
+ {ok,State};
+do_handle_data("echo_ml_no_prompt "++ Data,State) ->
+ Lines = string:tokens(Data," "),
+ ReturnData = string:join(Lines,"\n"),
+ send(ReturnData,State),
+ {ok,State};
+do_handle_data([],State) ->
+ send("> ",State),
+ {ok,State};
+do_handle_data(_Data,State) ->
+ send("error: unknown command\r\n> ",State),
+ {ok,State}.
+
+check_user(User,State) ->
+ case lists:keyfind(User,1,State#state.users) of
+ {User,Pwd} ->
+ dbg("user ok\n"),
+ send("Password: ",State),
+ {ok,State#state{authorized={user,Pwd}}};
+ false ->
+ throw({error,unknown_user})
+ end.
+
+check_pwd(Pwd,#state{authorized={user,Pwd}}=State) ->
+ dbg("password ok\n"),
+ send("Welcome to the ultimate telnet server!\r\n> ",State),
+ {ok,State#state{authorized=true}};
+check_pwd(_,_State) ->
+ throw({error,authentication}).
+
+send(Data,State) ->
+ dbg("Server sending: ~p~n",[Data]),
+ case gen_tcp:send(State#state.client,Data) of
+ ok ->
+ ok;
+ {error,Error} ->
+ throw({error,send,Error})
+ end.
+
+get_line([$\r,$\n|Rest],Acc) ->
+ {lists:reverse(Acc),Rest};
+get_line([$\r,0|Rest],Acc) ->
+ {lists:reverse(Acc),Rest};
+get_line([$\n|Rest],Acc) ->
+ {lists:reverse(Acc),Rest};
+get_line([H|T],Acc) ->
+ get_line(T,[H|Acc]);
+get_line([],_) ->
+ false.
+
+dbg(_F) ->
+ io:format(_F).
+dbg(_F,_A) ->
+ io:format(_F,_A).
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
index 3dd5ed182e..97a9188ee7 100644
--- a/lib/compiler/src/beam_receive.erl
+++ b/lib/compiler/src/beam_receive.erl
@@ -151,20 +151,20 @@ opt_recv(Is, Regs, D) ->
opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) ->
R = regs_kill_not_live(0, R0),
- case regs_to_list(R) of
- [{y,_}=RefReg] ->
- %% We now have the new reference in the Y register RefReg
+ case regs_empty(R) of
+ false ->
+ %% We now have the new reference in Y registers
%% and the current instruction is the beginning of a
%% receive statement. We must now verify that only messages
%% that contain the reference will be matched.
- case opt_ref_used(Is, RefReg, Fail, D) of
+ case opt_ref_used(Is, R, Fail, D) of
false ->
no;
true ->
RecvSet = {recv_set,{f,L}},
{yes,reverse(Acc, [RecvSet,Lbl,Loop|Is]),L}
end;
- [] ->
+ true ->
no
end;
opt_recv([I|Is], D, R0, L0, Acc) ->
@@ -226,9 +226,9 @@ opt_update_regs_bl([{set,Ds,_,_}|Is], Regs0) ->
opt_update_regs_bl(Is, Regs);
opt_update_regs_bl([], Regs) -> Regs.
-%% opt_ref_used([Instruction], RefRegister, FailLabel, LabelIndex) -> true|false
+%% opt_ref_used([Instruction], RefRegs, FailLabel, LabelIndex) -> true|false
%% Return 'true' if it is certain that only messages that contain the same
-%% reference as in RefRegister can be matched out. Otherwise return 'false'.
+%% reference as in RefRegs can be matched out. Otherwise return 'false'.
%%
%% Basically, we follow all possible paths through the receive statement.
%% If all paths are safe, we return 'true'.
@@ -236,7 +236,7 @@ opt_update_regs_bl([], Regs) -> Regs.
%% A branch to FailLabel is safe, because it exits the receive statement
%% and no further message may be matched out.
%%
-%% If a path hits an comparision between RefRegister and part of the message,
+%% If a path hits an comparision between RefRegs and part of the message,
%% that path is safe (any messages that may be matched further down the
%% path is guaranteed to contain the reference).
%%
@@ -245,11 +245,11 @@ opt_update_regs_bl([], Regs) -> Regs.
%% we hit an unrecognized instruction, we also give up and return
%% 'false' (the optimization may be unsafe).
-opt_ref_used(Is, RefReg, Fail, D) ->
+opt_ref_used(Is, RefRegs, Fail, D) ->
Done = gb_sets:singleton(Fail),
Regs = regs_init_x0(),
try
- _ = opt_ref_used_1(Is, RefReg, D, Done, Regs),
+ _ = opt_ref_used_1(Is, RefRegs, D, Done, Regs),
true
catch
throw:not_used ->
@@ -258,37 +258,39 @@ opt_ref_used(Is, RefReg, Fail, D) ->
%% This functions only returns if all paths through the receive
%% statement are safe, and throws an 'not_used' term otherwise.
-opt_ref_used_1([{block,Bl}|Is], RefReg, D, Done, Regs0) ->
+opt_ref_used_1([{block,Bl}|Is], RefRegs, D, Done, Regs0) ->
Regs = opt_ref_used_bl(Bl, Regs0),
- opt_ref_used_1(Is, RefReg, D, Done, Regs);
-opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefReg, Regs) of
+ opt_ref_used_1(Is, RefRegs, D, Done, Regs);
+opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is],
+ RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
+ case is_ref_msg_comparison(Args, RefRegs, Regs) of
false ->
- opt_ref_used_1(Is, RefReg, D, Done, Regs);
+ opt_ref_used_1(Is, RefRegs, D, Done, Regs);
true ->
%% The instructions that follow (Is) can only be executed
- %% if the message contains the same reference as in RefReg.
+ %% if the message contains the same reference as in RefRegs.
Done
end;
-opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefReg, Regs) of
+opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is],
+ RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
+ case is_ref_msg_comparison(Args, RefRegs, Regs) of
false ->
- opt_ref_used_at(Fail, RefReg, D, Done, Regs);
+ opt_ref_used_at(Fail, RefRegs, D, Done, Regs);
true ->
Done
end;
-opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs),
- opt_ref_used_1(Is, RefReg, D, Done, Regs);
-opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefReg, D, Done, Regs) ->
+opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
+ opt_ref_used_1(Is, RefRegs, D, Done, Regs);
+opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefRegs, D, Done, Regs) ->
Lbls = [F || {f,F} <- List] ++ [Fail],
- opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs);
-opt_ref_used_1([{label,Lbl}|Is], RefReg, D, Done, Regs) ->
+ opt_ref_used_in_all(Lbls, RefRegs, D, Done, Regs);
+opt_ref_used_1([{label,Lbl}|Is], RefRegs, D, Done, Regs) ->
case gb_sets:is_member(Lbl, Done) of
true -> Done;
- false -> opt_ref_used_1(Is, RefReg, D, Done, Regs)
+ false -> opt_ref_used_1(Is, RefRegs, D, Done, Regs)
end;
opt_ref_used_1([{loop_rec_end,_}|_], _, _, Done, _) ->
Done;
@@ -296,27 +298,25 @@ opt_ref_used_1([_I|_], _RefReg, _D, _Done, _Regs) ->
%% The optimization may be unsafe.
throw(not_used).
-%% is_ref_msg_comparison(Args, RefReg, RegisterSet) -> true|false.
+%% is_ref_msg_comparison(Args, RefRegs, RegisterSet) -> true|false.
%% Return 'true' if Args denotes a comparison between the
%% reference and message or part of the message.
-is_ref_msg_comparison([R,RefReg], RefReg, Regs) ->
- regs_is_member(R, Regs);
-is_ref_msg_comparison([RefReg,R], RefReg, Regs) ->
- regs_is_member(R, Regs);
-is_ref_msg_comparison([_,_], _, _) -> false.
-
-opt_ref_used_in_all([L|Ls], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_at(L, RefReg, D, Done0, Regs),
- opt_ref_used_in_all(Ls, RefReg, D, Done, Regs);
+is_ref_msg_comparison([R1,R2], RefRegs, Regs) ->
+ (regs_is_member(R2, RefRegs) andalso regs_is_member(R1, Regs)) orelse
+ (regs_is_member(R1, RefRegs) andalso regs_is_member(R2, Regs)).
+
+opt_ref_used_in_all([L|Ls], RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_at(L, RefRegs, D, Done0, Regs),
+ opt_ref_used_in_all(Ls, RefRegs, D, Done, Regs);
opt_ref_used_in_all([], _, _, Done, _) -> Done.
-opt_ref_used_at(Fail, RefReg, D, Done0, Regs) ->
+opt_ref_used_at(Fail, RefRegs, D, Done0, Regs) ->
case gb_sets:is_member(Fail, Done0) of
true ->
Done0;
false ->
Is = beam_utils:code_at(Fail, D),
- Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs),
+ Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
gb_sets:add(Fail, Done)
end.
@@ -408,15 +408,3 @@ regs_all_members([], _) -> true.
regs_is_member({x,N}, {Regs,_}) -> Regs band (1 bsl N) =/= 0;
regs_is_member({y,N}, {_,Regs}) -> Regs band (1 bsl N) =/= 0;
regs_is_member(_, _) -> false.
-
-%% regs_to_list(RegisterSet) -> [Register]
-%% Convert the register set to an explicit list of registers.
-regs_to_list({Xregs,Yregs}) ->
- regs_to_list_1(Xregs, 0, x, regs_to_list_1(Yregs, 0, y, [])).
-
-regs_to_list_1(0, _, _, Acc) ->
- Acc;
-regs_to_list_1(Regs, N, Tag, Acc) when (Regs band 1) =:= 1 ->
- regs_to_list_1(Regs bsr 1, N+1, Tag, [{Tag,N}|Acc]);
-regs_to_list_1(Regs, N, Tag, Acc) ->
- regs_to_list_1(Regs bsr 1, N+1, Tag, Acc).
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 745f1d5cf9..2ca403de54 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1197,9 +1197,9 @@ abstract_code(#compile{code=Code,options=Opts,ofile=OFile}) ->
encrypt_abs_code(Abstr, Key0) ->
try
- {Mode,RealKey} = generate_key(Key0),
+ RealKey = generate_key(Key0),
case start_crypto() of
- ok -> {ok,encrypt(Mode, RealKey, Abstr)};
+ ok -> {ok,encrypt(RealKey, Abstr)};
{error,_}=E -> E
end
catch
@@ -1216,19 +1216,19 @@ start_crypto() ->
{error,[{none,?MODULE,no_crypto}]}
end.
-generate_key({Mode,String}) when is_atom(Mode), is_list(String) ->
- {Mode,beam_lib:make_crypto_key(Mode, String)};
+generate_key({Type,String}) when is_atom(Type), is_list(String) ->
+ beam_lib:make_crypto_key(Type, String);
generate_key(String) when is_list(String) ->
generate_key({des3_cbc,String}).
-encrypt(des3_cbc=Mode, {K1,K2,K3, IVec}, Bin0) ->
- Bin1 = case byte_size(Bin0) rem 8 of
+encrypt({des3_cbc=Type,Key,IVec,BlockSize}, Bin0) ->
+ Bin1 = case byte_size(Bin0) rem BlockSize of
0 -> Bin0;
- N -> list_to_binary([Bin0,random_bytes(8-N)])
+ N -> list_to_binary([Bin0,random_bytes(BlockSize-N)])
end,
- Bin = crypto:des3_cbc_encrypt(K1, K2, K3, IVec, Bin1),
- ModeString = atom_to_list(Mode),
- list_to_binary([0,length(ModeString),ModeString,Bin]).
+ Bin = crypto:block_encrypt(Type, Key, IVec, Bin1),
+ TypeString = atom_to_list(Type),
+ list_to_binary([0,length(TypeString),TypeString,Bin]).
random_bytes(N) ->
{A,B,C} = now(),
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 229e5a98a1..c635d13c89 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -492,6 +492,16 @@ encrypted_abstr_1(Simple, Target) ->
?line {error,beam_lib,{key_missing_or_invalid,"simple.beam",abstract_code}} =
beam_lib:chunks("simple.beam", [abstract_code]),
?line ok = file:set_cwd(OldCwd),
+
+ %% Test key compatibility by reading a BEAM file produced before
+ %% the update to the new crypto functions.
+ install_crypto_key("an old key"),
+ KeyCompat = filename:join(filename:dirname(Simple),
+ "key_compatibility"),
+ {ok,{key_compatibility,[Chunk]}} = beam_lib:chunks(KeyCompat,
+ [abstract_code]),
+ {abstract_code,{raw_abstract_v1,_}} = Chunk,
+
ok.
diff --git a/lib/compiler/test/compile_SUITE_data/key_compatibility.beam b/lib/compiler/test/compile_SUITE_data/key_compatibility.beam
new file mode 100644
index 0000000000..28329d2423
--- /dev/null
+++ b/lib/compiler/test/compile_SUITE_data/key_compatibility.beam
Binary files differ
diff --git a/lib/compiler/test/compile_SUITE_data/key_compatibility.erl b/lib/compiler/test/compile_SUITE_data/key_compatibility.erl
new file mode 100644
index 0000000000..e2931f1b12
--- /dev/null
+++ b/lib/compiler/test/compile_SUITE_data/key_compatibility.erl
@@ -0,0 +1,8 @@
+-module(key_compatibility).
+-export([main/0]).
+
+%% Compile like this:
+%% erlc +'{debug_info_key,"an old key"}' key_compatibility.erl
+
+main() ->
+ ok.
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index b91f2922fb..e60584d4ab 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -188,7 +188,7 @@ ref_opt(Config) when is_list(Config) ->
ref_opt_1(Config) ->
?line DataDir = ?config(data_dir, Config),
?line PrivDir = ?config(priv_dir, Config),
- ?line Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.erl"])),
+ Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.{erl,S}"])),
?line test_lib:p_run(fun(Src) ->
do_ref_opt(Src, PrivDir)
end, Sources),
@@ -196,10 +196,15 @@ ref_opt_1(Config) ->
do_ref_opt(Source, PrivDir) ->
try
- {ok,Mod} = c:c(Source, [{outdir,PrivDir}]),
+ Ext = filename:extension(Source),
+ {ok,Mod} = compile:file(Source, [report_errors,report_warnings,
+ {outdir,PrivDir}] ++
+ [from_asm || Ext =:= ".S" ]),
+ Base = filename:rootname(filename:basename(Source), Ext),
+ code:purge(list_to_atom(Base)),
+ BeamFile = filename:join(PrivDir, Base),
+ code:load_abs(BeamFile),
ok = Mod:Mod(),
- Base = filename:rootname(filename:basename(Source), ".erl"),
- BeamFile = filename:join(PrivDir, Base),
{beam_file,Mod,_,_,_,Code} = beam_disasm:file(BeamFile),
case Base of
"no_"++_ ->
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
new file mode 100644
index 0000000000..fd14228135
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
@@ -0,0 +1,71 @@
+{module, yes_14}. %% version = 0
+
+{exports, [{f,2},{module_info,0},{module_info,1},{yes_14,0}]}.
+
+{attributes, []}.
+
+{labels, 12}.
+
+
+{function, yes_14, 0, 2}.
+ {label,1}.
+ {func_info,{atom,yes_14},{atom,yes_14},0}.
+ {label,2}.
+ {move,{atom,ok},{x,0}}.
+ return.
+
+
+{function, f, 2, 4}.
+ {label,3}.
+ {func_info,{atom,yes_14},{atom,f},2}.
+ {label,4}.
+ {allocate_heap,2,3,2}.
+ {move,{x,0},{y,1}}.
+ {put_tuple,2,{y,0}}.
+ {put,{atom,data}}.
+ {put,{x,1}}.
+ {call_ext,0,{extfunc,erlang,make_ref,0}}. % Ref in [x0]
+ {test_heap,4,1}.
+ {put_tuple,3,{x,1}}.
+ {put,{atom,request}}.
+ {put,{x,0}}.
+ {put,{y,0}}.
+ {move,{x,0},{y,0}}. % Ref in [x0,y0]
+ {move,{y,1},{x,0}}. % Ref in [y0]
+ {kill,{y,1}}.
+ send.
+ {move,{y,0},{x,0}}. % Ref in [x0,y0]
+ {move,{x,0},{y,1}}. % Ref in [x0,y0,y1]
+ {label,5}.
+ {loop_rec,{f,7},{x,0}}. % Ref in [y0,y1]
+ {test,is_tuple,{f,6},[{x,0}]}.
+ {test,test_arity,{f,6},[{x,0},2]}.
+ {get_tuple_element,{x,0},0,{x,1}}.
+ {get_tuple_element,{x,0},1,{x,2}}.
+ {test,is_eq_exact,{f,6},[{x,1},{atom,reply}]}.
+ {test,is_eq_exact,{f,6},[{x,2},{y,1}]}.
+ remove_message.
+ {move,{atom,ok},{x,0}}.
+ {deallocate,2}.
+ return.
+ {label,6}.
+ {loop_rec_end,{f,5}}.
+ {label,7}.
+ {wait,{f,5}}.
+
+
+{function, module_info, 0, 9}.
+ {label,8}.
+ {func_info,{atom,yes_14},{atom,module_info},0}.
+ {label,9}.
+ {move,{atom,yes_14},{x,0}}.
+ {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
+
+
+{function, module_info, 1, 11}.
+ {label,10}.
+ {func_info,{atom,yes_14},{atom,module_info},1}.
+ {label,11}.
+ {move,{x,0},{x,1}}.
+ {move,{atom,yes_14},{x,0}}.
+ {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl
index 3f02fba6a6..5070e3e546 100644
--- a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl
@@ -24,11 +24,7 @@ do_call(Process, Label, Request, Timeout) ->
{'DOWN', Mref, _, _, Reason} ->
exit(Reason)
after Timeout ->
- erlang:demonitor(Mref),
- receive
- {'DOWN', Mref, _, _, _} -> true
- after 0 -> true
- end,
+ erlang:demonitor(Mref, [flush]),
exit(timeout)
end
catch
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index fac77308f6..98ebb21f29 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -74,6 +74,19 @@
# define HAVE_DES_ede3_cfb_encrypt
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x009080ffL \
+ && !defined(OPENSSL_NO_EC) \
+ && !defined(OPENSSL_NO_ECDH) \
+ && !defined(OPENSSL_NO_ECDSA)
+# define HAVE_EC
+#endif
+
+#if defined(HAVE_EC)
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#endif
+
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -192,7 +205,7 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -209,13 +222,19 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
/* helpers */
@@ -247,6 +266,11 @@ static void hmac_sha512(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
unsigned char *hmacbuf);
#endif
+#ifdef HAVE_EC
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr);
+#endif
static int library_refc = 0; /* number of users of this dynamic library */
@@ -311,7 +335,7 @@ static ErlNifFunc nif_funcs[] = {
{"strong_rand_mpint_nif", 3, strong_rand_mpint_nif},
{"rand_uniform_nif", 2, rand_uniform_nif},
{"mod_exp_nif", 4, mod_exp_nif},
- {"dss_verify", 4, dss_verify},
+ {"dss_verify_nif", 4, dss_verify_nif},
{"rsa_verify_nif", 4, rsa_verify_nif},
{"aes_cbc_crypt", 4, aes_cbc_crypt},
{"exor", 2, exor},
@@ -325,16 +349,120 @@ static ErlNifFunc nif_funcs[] = {
{"rsa_private_crypt", 4, rsa_private_crypt},
{"dh_generate_parameters_nif", 2, dh_generate_parameters_nif},
{"dh_check", 1, dh_check},
- {"dh_generate_key_nif", 2, dh_generate_key_nif},
+ {"dh_generate_key_nif", 3, dh_generate_key_nif},
{"dh_compute_key_nif", 3, dh_compute_key_nif},
{"srp_value_B_nif", 5, srp_value_B_nif},
- {"srp_client_secret_nif", 7, srp_client_secret_nif},
- {"srp_server_secret_nif", 5, srp_server_secret_nif},
+ {"srp_user_secret_nif", 7, srp_user_secret_nif},
+ {"srp_host_secret_nif", 5, srp_host_secret_nif},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
- {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt}
+ {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt},
+
+ {"ec_key_to_term_nif", 1, ec_key_to_term_nif},
+ {"term_to_ec_key_nif", 3, term_to_ec_key_nif},
+ {"ec_key_generate", 1, ec_key_generate},
+ {"ecdsa_sign_nif", 3, ecdsa_sign_nif},
+ {"ecdsa_verify_nif", 4, ecdsa_verify_nif},
+ {"ecdh_compute_key_nif", 2, ecdh_compute_key_nif}
+};
+
+#if defined(HAVE_EC)
+struct nid_map {
+ char *name;
+ int nid;
+ ERL_NIF_TERM atom;
+};
+
+static struct nid_map ec_curves[] = {
+ /* prime field curves */
+ /* secg curves */
+ { "secp112r1", NID_secp112r1 },
+ { "secp112r2", NID_secp112r2 },
+ { "secp128r1", NID_secp128r1 },
+ { "secp128r2", NID_secp128r2 },
+ { "secp160k1", NID_secp160k1 },
+ { "secp160r1", NID_secp160r1 },
+ { "secp160r2", NID_secp160r2 },
+ /* SECG secp192r1 is the same as X9.62 prime192v1 */
+ { "secp192r1", NID_X9_62_prime192v1 },
+ { "secp192k1", NID_secp192k1 },
+ { "secp224k1", NID_secp224k1 },
+ { "secp224r1", NID_secp224r1 },
+ { "secp256k1", NID_secp256k1 },
+ /* SECG secp256r1 is the same as X9.62 prime256v1 */
+ { "secp256r1", NID_X9_62_prime256v1 },
+ { "secp384r1", NID_secp384r1 },
+ { "secp521r1", NID_secp521r1 },
+ /* X9.62 curves */
+ { "prime192v1", NID_X9_62_prime192v1 },
+ { "prime192v2", NID_X9_62_prime192v2 },
+ { "prime192v3", NID_X9_62_prime192v3 },
+ { "prime239v1", NID_X9_62_prime239v1 },
+ { "prime239v2", NID_X9_62_prime239v2 },
+ { "prime239v3", NID_X9_62_prime239v3 },
+ { "prime256v1", NID_X9_62_prime256v1 },
+ /* characteristic two field curves */
+ /* NIST/SECG curves */
+ { "sect113r1", NID_sect113r1 },
+ { "sect113r2", NID_sect113r2 },
+ { "sect131r1", NID_sect131r1 },
+ { "sect131r2", NID_sect131r2 },
+ { "sect163k1", NID_sect163k1 },
+ { "sect163r1", NID_sect163r1 },
+ { "sect163r2", NID_sect163r2 },
+ { "sect193r1", NID_sect193r1 },
+ { "sect193r2", NID_sect193r2 },
+ { "sect233k1", NID_sect233k1 },
+ { "sect233r1", NID_sect233r1 },
+ { "sect239k1", NID_sect239k1 },
+ { "sect283k1", NID_sect283k1 },
+ { "sect283r1", NID_sect283r1 },
+ { "sect409k1", NID_sect409k1 },
+ { "sect409r1", NID_sect409r1 },
+ { "sect571k1", NID_sect571k1 },
+ { "sect571r1", NID_sect571r1 },
+ /* X9.62 curves */
+ { "c2pnb163v1", NID_X9_62_c2pnb163v1 },
+ { "c2pnb163v2", NID_X9_62_c2pnb163v2 },
+ { "c2pnb163v3", NID_X9_62_c2pnb163v3 },
+ { "c2pnb176v1", NID_X9_62_c2pnb176v1 },
+ { "c2tnb191v1", NID_X9_62_c2tnb191v1 },
+ { "c2tnb191v2", NID_X9_62_c2tnb191v2 },
+ { "c2tnb191v3", NID_X9_62_c2tnb191v3 },
+ { "c2pnb208w1", NID_X9_62_c2pnb208w1 },
+ { "c2tnb239v1", NID_X9_62_c2tnb239v1 },
+ { "c2tnb239v2", NID_X9_62_c2tnb239v2 },
+ { "c2tnb239v3", NID_X9_62_c2tnb239v3 },
+ { "c2pnb272w1", NID_X9_62_c2pnb272w1 },
+ { "c2pnb304w1", NID_X9_62_c2pnb304w1 },
+ { "c2tnb359v1", NID_X9_62_c2tnb359v1 },
+ { "c2pnb368w1", NID_X9_62_c2pnb368w1 },
+ { "c2tnb431r1", NID_X9_62_c2tnb431r1 },
+ /* the WAP/WTLS curves
+ * [unlike SECG, spec has its own OIDs for curves from X9.62] */
+ { "wtls1", NID_wap_wsg_idm_ecid_wtls1 },
+ { "wtls3", NID_wap_wsg_idm_ecid_wtls3 },
+ { "wtls4", NID_wap_wsg_idm_ecid_wtls4 },
+ { "wtls5", NID_wap_wsg_idm_ecid_wtls5 },
+ { "wtls6", NID_wap_wsg_idm_ecid_wtls6 },
+ { "wtls7", NID_wap_wsg_idm_ecid_wtls7 },
+ { "wtls8", NID_wap_wsg_idm_ecid_wtls8 },
+ { "wtls9", NID_wap_wsg_idm_ecid_wtls9 },
+ { "wtls10", NID_wap_wsg_idm_ecid_wtls10 },
+ { "wtls11", NID_wap_wsg_idm_ecid_wtls11 },
+ { "wtls12", NID_wap_wsg_idm_ecid_wtls12 },
+ /* IPSec curves */
+ { "ipsec3", NID_ipsec3 },
+ { "ipsec4", NID_ipsec4 }
+};
+
+#define EC_CURVES_CNT (sizeof(ec_curves)/sizeof(struct nid_map))
+
+struct nif_ec_key {
+ EC_KEY *key;
};
+#endif
ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
@@ -368,6 +496,7 @@ static ERL_NIF_TERM atom_sha256;
static ERL_NIF_TERM atom_sha384;
static ERL_NIF_TERM atom_sha512;
static ERL_NIF_TERM atom_md5;
+static ERL_NIF_TERM atom_md4;
static ERL_NIF_TERM atom_ripemd160;
static ERL_NIF_TERM atom_error;
static ERL_NIF_TERM atom_rsa_pkcs1_padding;
@@ -386,6 +515,19 @@ static ERL_NIF_TERM atom_none;
static ERL_NIF_TERM atom_notsup;
static ERL_NIF_TERM atom_digest;
+static ERL_NIF_TERM atom_ec;
+
+#if defined(HAVE_EC)
+static ERL_NIF_TERM atom_prime_field;
+static ERL_NIF_TERM atom_characteristic_two_field;
+static ERL_NIF_TERM atom_tpbasis;
+static ERL_NIF_TERM atom_ppbasis;
+static ERL_NIF_TERM atom_onbasis;
+
+static ErlNifResourceType* res_type_ec_key;
+static void ec_key_dtor(ErlNifEnv* env, void* obj);
+#endif
+
/*
#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")
#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1)
@@ -415,6 +557,7 @@ static void error_handler(void* null, const char* errstr)
static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
+ int i;
ErlNifSysInfo sys_info;
get_crypto_callbacks_t* funcp;
struct crypto_callbacks* ccb;
@@ -448,6 +591,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_sha256 = enif_make_atom(env,"sha256");
atom_sha384 = enif_make_atom(env,"sha384");
atom_sha512 = enif_make_atom(env,"sha512");
+ atom_md4 = enif_make_atom(env,"md4");
atom_md5 = enif_make_atom(env,"md5");
atom_ripemd160 = enif_make_atom(env,"ripemd160");
atom_error = enif_make_atom(env,"error");
@@ -466,6 +610,23 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_notsup = enif_make_atom(env,"notsup");
atom_digest = enif_make_atom(env,"digest");
+#if defined(HAVE_EC)
+ atom_ec = enif_make_atom(env,"ec");
+ atom_prime_field = enif_make_atom(env,"prime_field");
+ atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
+ atom_tpbasis = enif_make_atom(env,"tpbasis");
+ atom_ppbasis = enif_make_atom(env,"ppbasis");
+ atom_onbasis = enif_make_atom(env,"onbasis");
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ ec_curves[i].atom = enif_make_atom(env,ec_curves[i].name);
+
+ res_type_ec_key = enif_open_resource_type(env,NULL,"crypto.EC_KEY",
+ ec_key_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+#endif
+
init_digest_types(env);
init_algorithms_types();
@@ -549,12 +710,12 @@ static void unload(ErlNifEnv* env, void* priv_data)
}
static int algos_cnt;
-static ERL_NIF_TERM algos[7]; /* increase when extending the list */
+static ERL_NIF_TERM algos[9]; /* increase when extending the list */
static void init_algorithms_types(void)
{
algos_cnt = 0;
-
+ algos[algos_cnt++] = atom_md4;
algos[algos_cnt++] = atom_md5;
algos[algos_cnt++] = atom_sha;
algos[algos_cnt++] = atom_ripemd160;
@@ -570,6 +731,9 @@ static void init_algorithms_types(void)
#ifdef HAVE_SHA512
algos[algos_cnt++] = atom_sha512;
#endif
+#if defined(HAVE_EC)
+ algos[algos_cnt++] = atom_ec;
+#endif
}
static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -1631,13 +1795,7 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
return ret;
}
-static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin)
-{
- return enif_inspect_binary(env, term, bin) &&
- bin->size >= 4 && get_int32(bin->data) == bin->size-4;
-}
-
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */
ErlNifBinary data_bin, sign_bin;
BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL;
@@ -1660,10 +1818,10 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env, argv[1], &data_bin)) {
+ if (!enif_inspect_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -1675,15 +1833,15 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
return enif_make_badarg(env);
}
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_p)
+ || !get_bn_from_bin(env, head, &dsa_p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_q)
+ || !get_bn_from_bin(env, head, &dsa_q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_g)
+ || !get_bn_from_bin(env, head, &dsa_g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_y)
+ || !get_bn_from_bin(env, head, &dsa_y)
|| !enif_is_empty_list(env,tail)) {
if (dsa_p) BN_free(dsa_p);
@@ -1700,7 +1858,7 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
dsa->priv_key = NULL;
dsa->pub_key = dsa_y;
i = DSA_verify(0, digest, SHA_DIGEST_LENGTH,
- sign_bin.data+4, sign_bin.size-4, dsa);
+ sign_bin.data, sign_bin.size, dsa);
DSA_free(dsa);
return(i > 0) ? atom_true : atom_false;
}
@@ -1826,11 +1984,11 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
rsa = RSA_new();
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -1846,9 +2004,9 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
digest = data_bin.data;
}
- else if (inspect_mpint(env, argv[1], &data_bin)) {
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
else {
ret = enif_make_badarg(env);
@@ -1856,7 +2014,7 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
i = RSA_verify(digp->NID_type, digest, digp->len,
- sign_bin.data+4, sign_bin.size-4, rsa);
+ sign_bin.data, sign_bin.size, rsa);
ret = (i==1 ? atom_true : atom_false);
@@ -2001,22 +2159,22 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
ERL_NIF_TERM head, tail;
if (!enif_get_list_cell(env, key, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->d)
+ || !get_bn_from_bin(env, head, &rsa->d)
|| (!enif_is_empty_list(env, tail) &&
(!enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->p)
+ || !get_bn_from_bin(env, head, &rsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->q)
+ || !get_bn_from_bin(env, head, &rsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmp1)
+ || !get_bn_from_bin(env, head, &rsa->dmp1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmq1)
+ || !get_bn_from_bin(env, head, &rsa->dmq1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->iqmp)
+ || !get_bn_from_bin(env, head, &rsa->iqmp)
|| !enif_is_empty_list(env, tail)))) {
return 0;
}
@@ -2053,11 +2211,11 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
rsa = RSA_new();
@@ -2112,10 +2270,10 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -2133,13 +2291,13 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
dsa->pub_key = NULL;
if (!enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->p)
+ || !get_bn_from_bin(env, head, &dsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->q)
+ || !get_bn_from_bin(env, head, &dsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->g)
+ || !get_bn_from_bin(env, head, &dsa->g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->priv_key)
+ || !get_bn_from_bin(env, head, &dsa->priv_key)
|| !enif_is_empty_list(env,tail)) {
DSA_free(dsa);
return enif_make_badarg(env);
@@ -2187,9 +2345,9 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER
if (!enif_inspect_binary(env, argv[0], &data_bin)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env,tail)
|| !rsa_pad(argv[2], &padding)) {
@@ -2286,14 +2444,12 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
}
p_len = BN_num_bytes(dh_params->p);
g_len = BN_num_bytes(dh_params->g);
- p_ptr = enif_make_new_binary(env, p_len+4, &ret_p);
- g_ptr = enif_make_new_binary(env, g_len+4, &ret_g);
- put_int32(p_ptr, p_len);
- put_int32(g_ptr, g_len);
- BN_bn2bin(dh_params->p, p_ptr+4);
- BN_bn2bin(dh_params->g, g_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr+4, p_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr+4, g_len);
+ p_ptr = enif_make_new_binary(env, p_len, &ret_p);
+ g_ptr = enif_make_new_binary(env, g_len, &ret_g);
+ BN_bn2bin(dh_params->p, p_ptr);
+ BN_bn2bin(dh_params->g, g_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr, p_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr, g_len);
DH_free(dh_params);
return enif_make_list2(env, ret_p, ret_g);
}
@@ -2305,9 +2461,9 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
ERL_NIF_TERM ret, head, tail;
if (!enif_get_list_cell(env, argv[0], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env,tail)) {
DH_free(dh_params);
@@ -2329,19 +2485,21 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
}
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (PrivKey, DHParams=[P,G]) */
+{/* (PrivKey, DHParams=[P,G], Mpint) */
DH* dh_params = DH_new();
int pub_len, prv_len;
unsigned char *pub_ptr, *prv_ptr;
ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;
+ int mpint; /* 0 or 4 */
- if (!(get_bn_from_mpint(env, argv[0], &dh_params->priv_key)
+ if (!(get_bn_from_bin(env, argv[0], &dh_params->priv_key)
|| argv[0] == atom_undefined)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
- || !enif_is_empty_list(env, tail)) {
+ || !get_bn_from_bin(env, head, &dh_params->g)
+ || !enif_is_empty_list(env, tail)
+ || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)) {
DH_free(dh_params);
return enif_make_badarg(env);
}
@@ -2349,14 +2507,16 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_
if (DH_generate_key(dh_params)) {
pub_len = BN_num_bytes(dh_params->pub_key);
prv_len = BN_num_bytes(dh_params->priv_key);
- pub_ptr = enif_make_new_binary(env, pub_len+4, &ret_pub);
- prv_ptr = enif_make_new_binary(env, prv_len+4, &ret_prv);
- put_int32(pub_ptr, pub_len);
- put_int32(prv_ptr, prv_len);
- BN_bn2bin(dh_params->pub_key, pub_ptr+4);
- BN_bn2bin(dh_params->priv_key, prv_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr+4, pub_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr+4, prv_len);
+ pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub);
+ prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv);
+ if (mpint) {
+ put_int32(pub_ptr, pub_len); pub_ptr += 4;
+ put_int32(prv_ptr, prv_len); prv_ptr += 4;
+ }
+ BN_bn2bin(dh_params->pub_key, pub_ptr);
+ BN_bn2bin(dh_params->priv_key, prv_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len);
ret = enif_make_tuple2(env, ret_pub, ret_prv);
}
else {
@@ -2374,12 +2534,12 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
ErlNifBinary ret_bin;
ERL_NIF_TERM ret, head, tail;
- if (!get_bn_from_mpint(env, argv[0], &pubkey)
- || !get_bn_from_mpint(env, argv[1], &dh_params->priv_key)
+ if (!get_bn_from_bin(env, argv[0], &pubkey)
+ || !get_bn_from_bin(env, argv[1], &dh_params->priv_key)
|| !enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -2457,7 +2617,7 @@ static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
return ret;
}
-static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */
/*
<premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N
@@ -2537,7 +2697,7 @@ static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NI
return ret;
}
-static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Verifier, b, u, A, Prime) */
/*
<premaster secret> = (A * v^u) ^ b % N
@@ -2686,7 +2846,554 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
return ret;
}
+#if defined(HAVE_EC)
+static int term2curve_id(ERL_NIF_TERM nid)
+{
+ int i;
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ if (ec_curves[i].atom == nid)
+ return ec_curves[i].nid;
+
+ return 0;
+}
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)
+{
+ EC_KEY *key = NULL;
+ int nid = 0;
+ int c_arity = -1;
+ const ERL_NIF_TERM* curve;
+ ErlNifBinary seed;
+ BIGNUM *p = NULL;
+ BIGNUM *a = NULL;
+ BIGNUM *b = NULL;
+ BIGNUM *bn_order = NULL;
+ BIGNUM *cofactor = NULL;
+ EC_GROUP *group = NULL;
+ EC_POINT *point = NULL;
+
+ if (enif_is_atom(env, curve_arg)) {
+ nid = term2curve_id(curve_arg);
+ if (nid == 0)
+ return NULL;
+ key = EC_KEY_new_by_curve_name(nid);
+ }
+ else if (enif_is_tuple(env, curve_arg)
+ && enif_get_tuple(env,curve_arg,&c_arity,&curve)
+ && c_arity == 5
+ && get_bn_from_bin(env, curve[3], &bn_order)
+ && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) {
+ //* {Field, Prime, Point, Order, CoFactor} = Curve */
+
+ int f_arity = -1;
+ const ERL_NIF_TERM* field;
+ int p_arity = -1;
+ const ERL_NIF_TERM* prime;
+
+ long field_bits;
+
+ /* {A, B, Seed} = Prime */
+ if (!enif_get_tuple(env,curve[1],&p_arity,&prime)
+ || !get_bn_from_bin(env, prime[0], &a)
+ || !get_bn_from_bin(env, prime[1], &b))
+ goto out_err;
+
+ if (!enif_get_tuple(env,curve[0],&f_arity,&field))
+ goto out_err;
+
+ if (f_arity == 2 && field[0] == atom_prime_field) {
+ /* {prime_field, Prime} */
+
+ if (!get_bn_from_bin(env, field[1], &p))
+ goto out_err;
+
+ if (BN_is_negative(p) || BN_is_zero(p))
+ goto out_err;
+
+ field_bits = BN_num_bits(p);
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ /* create the EC_GROUP structure */
+ group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+
+ } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) {
+ /* {characteristic_two_field, M, Basis} */
+
+ int b_arity = -1;
+ const ERL_NIF_TERM* basis;
+ unsigned int k1, k2, k3;
+
+ if ((p = BN_new()) == NULL)
+ goto out_err;
+
+ if (!enif_get_long(env, field[1], &field_bits)
+ || field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ if (enif_get_tuple(env,field[2],&b_arity,&basis)) {
+ if (b_arity == 2
+ && basis[0] == atom_tpbasis
+ && enif_get_uint(env, basis[1], &k1)) {
+ /* {tpbasis, k} = Basis */
+
+ if (!(field_bits > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else if (b_arity == 4
+ && basis[0] == atom_ppbasis
+ && enif_get_uint(env, basis[1], &k1)
+ && enif_get_uint(env, basis[2], &k2)
+ && enif_get_uint(env, basis[3], &k3)) {
+ /* {ppbasis, k1, k2, k3} = Basis */
+
+ if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, (int)k2)
+ || !BN_set_bit(p, (int)k3)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else
+ goto out_err;
+ } else if (field[2] == atom_onbasis) {
+ /* onbasis = Basis */
+ /* no parameters */
+ goto out_err;
+
+ } else
+ goto out_err;
+
+ group = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
+ } else
+ goto out_err;
+
+ if (enif_inspect_binary(env, prime[2], &seed)) {
+ EC_GROUP_set_seed(group, seed.data, seed.size);
+ }
+
+ if (!term2point(env, curve[2], group, &point))
+ goto out_err;
+
+ if (BN_is_negative(bn_order)
+ || BN_is_zero(bn_order)
+ || BN_num_bits(bn_order) > (int)field_bits + 1)
+ goto out_err;
+
+ if (!EC_GROUP_set_generator(group, point, bn_order, cofactor))
+ goto out_err;
+
+ EC_GROUP_set_asn1_flag(group, 0x0);
+
+ key = EC_KEY_new();
+ if (!key)
+ goto out_err;
+ EC_KEY_set_group(key, group);
+ }
+ else {
+ goto out_err;
+ }
+
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ key = NULL;
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (p) BN_free(p);
+ if (a) BN_free(a);
+ if (b) BN_free(b);
+ if (bn_order) BN_free(bn_order);
+ if (cofactor) BN_free(cofactor);
+ if (group) EC_GROUP_free(group);
+
+ return key;
+}
+
+
+static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn)
+{
+ unsigned dlen;
+ unsigned char* ptr;
+ ERL_NIF_TERM ret;
+
+ if (!bn)
+ return atom_undefined;
+
+ dlen = BN_num_bytes(bn);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn, ptr);
+
+ return ret;
+}
+
+static ERL_NIF_TERM point2term(ErlNifEnv* env,
+ const EC_GROUP *group,
+ const EC_POINT *point,
+ point_conversion_form_t form)
+{
+ unsigned dlen;
+ ErlNifBinary bin;
+
+ dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
+ if (dlen == 0)
+ return atom_undefined;
+
+ if (!enif_alloc_binary(dlen, &bin))
+ return enif_make_badarg(env);
+
+ if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) {
+ enif_release_binary(&bin);
+ return enif_make_badarg(env);
+ }
+
+ return enif_make_binary(env, &bin);
+}
+#endif
+
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ struct nif_ec_key *obj;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ const BIGNUM *priv_key = NULL;
+ ERL_NIF_TERM pub_key = atom_undefined;
+
+ if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ group = EC_KEY_get0_group(obj->key);
+ public_key = EC_KEY_get0_public_key(obj->key);
+ priv_key = EC_KEY_get0_private_key(obj->key);
+
+ if (group) {
+ if (public_key)
+ pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key));
+ }
+
+ return enif_make_tuple2(env, pub_key, bn2term(env, priv_key));
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr)
+{
+ int ret = 0;
+ ErlNifBinary bin;
+ EC_POINT *point;
+
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+
+ if ((*pptr = point = EC_POINT_new(group)) == NULL) {
+ return 0;
+ }
+
+ /* set the point conversion form */
+ EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01));
+
+ /* extract the ec point */
+ if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) {
+ EC_POINT_free(point);
+ *pptr = NULL;
+ } else
+ ret = 1;
+
+ return ret;
+}
+#endif
+
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ EC_KEY *key = NULL;
+ BIGNUM *priv_key = NULL;
+ EC_POINT *pub_key = NULL;
+ struct nif_ec_key *obj;
+ EC_GROUP *group = NULL;
+
+ if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key))
+ || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) {
+ goto out_err;
+ }
+
+ key = ec_key_new(env, argv[0]);
+
+ if (!key) {
+ goto out_err;
+ }
+
+ if (!group)
+ group = EC_GROUP_dup(EC_KEY_get0_group(key));
+
+ if (term2point(env, argv[2], group, &pub_key)) {
+ if (!EC_KEY_set_public_key(key, pub_key)) {
+ goto out_err;
+ }
+ }
+ if (argv[1] != atom_undefined
+ && !BN_is_zero(priv_key)) {
+ if (!EC_KEY_set_private_key(key, priv_key))
+ goto out_err;
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(key) == NULL)
+ {
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ pub_key = EC_POINT_new(group);
+ if (pub_key == NULL
+ || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))
+ || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)
+ || !EC_KEY_set_public_key(key, pub_key))
+ goto out_err;
+ }
+ }
+
+ obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ goto out_err;
+
+ obj->key = key;
+ ret = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ ret = enif_make_badarg(env);
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (priv_key) BN_clear_free(priv_key);
+ if (pub_key) EC_POINT_free(pub_key);
+ if (group) EC_GROUP_free(group);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ EC_KEY *key = ec_key_new(env, argv[0]);
+
+ if (key && EC_KEY_generate_key(key)) {
+ ERL_NIF_TERM term;
+ struct nif_ec_key *obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ return atom_error;
+ obj->key = key;
+ term = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+ return term;
+ }
+ else
+ return enif_make_badarg(env);
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static void ec_key_dtor(ErlNifEnv* env, void* obj)
+{
+ struct nif_ec_key *key = (struct nif_ec_key*) obj;
+ EC_KEY_free(key->key);
+}
+#endif
+
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, ret_bin;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned int dsa_s_len;
+ struct nif_ec_key *obj;
+ int i;
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t *digp;
+ unsigned char* digest;
+
+ digp = get_digest_type(argv[0]);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_get_resource(env, argv[2], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
+ return enif_make_badarg(env);
+ }
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+
+ enif_alloc_binary(ECDSA_size(obj->key), &ret_bin);
+
+ i = ECDSA_sign(digp->NID_type, digest, digp->len,
+ ret_bin.data, &dsa_s_len, obj->key);
+ if (i) {
+ if (dsa_s_len != ret_bin.size) {
+ enif_realloc_binary(&ret_bin, dsa_s_len);
+ }
+ return enif_make_binary(env, &ret_bin);
+ }
+ else {
+ enif_release_binary(&ret_bin);
+ return atom_error;
+ }
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Signature, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, sign_bin;
+ unsigned char hmacbuf[SHA512_LEN];
+ int i;
+ struct nif_ec_key *obj;
+ const ERL_NIF_TERM type = argv[0];
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t* digp = NULL;
+ unsigned char* digest = NULL;
+
+ digp = get_digest_type(type);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
+ || !enif_get_resource(env, argv[3], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+ else {
+ return enif_make_badarg(env);
+ }
+
+ i = ECDSA_verify(digp->NID_type, digest, digp->len,
+ sign_bin.data, sign_bin.size, obj->key);
+
+ return (i==1 ? atom_true : atom_false);
+#else
+ return atom_notsup;
+#endif
+}
+
+/*
+ (_OthersPublicKey, _MyPrivateKey)
+ (_OthersPublicKey, _MyEC_Point)
+*/
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ unsigned char *p;
+ struct nif_ec_key *other_key;
+ int field_size = 0;
+ int i;
+
+ EC_GROUP *group;
+ const BIGNUM *priv_key;
+ EC_POINT *my_ecpoint;
+ EC_KEY *other_ecdh = NULL;
+
+ if (!enif_get_resource(env, argv[1], res_type_ec_key, (void **)&other_key))
+ return enif_make_badarg(env);
+
+ group = EC_GROUP_dup(EC_KEY_get0_group(other_key->key));
+ priv_key = EC_KEY_get0_private_key(other_key->key);
+
+ if (!term2point(env, argv[0], group, &my_ecpoint)) {
+ goto out_err;
+ }
+
+ if ((other_ecdh = EC_KEY_new()) == NULL
+ || !EC_KEY_set_group(other_ecdh, group)
+ || !EC_KEY_set_private_key(other_ecdh, priv_key))
+ goto out_err;
+
+ field_size = EC_GROUP_get_degree(group);
+ if (field_size <= 0)
+ goto out_err;
+
+ p = enif_make_new_binary(env, (field_size+7)/8, &ret);
+ i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL);
+
+ if (i < 0)
+ goto out_err;
+out:
+ if (group) EC_GROUP_free(group);
+ if (my_ecpoint) EC_POINT_free(my_ecpoint);
+ if (other_ecdh) EC_KEY_free(other_ecdh);
+
+ return ret;
+
+out_err:
+ ret = enif_make_badarg(env);
+ goto out;
+#else
+ return atom_notsup;
+#endif
+}
/* HMAC */
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 29fc885152..bdccfee341 100755..100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -22,263 +22,234 @@
</legalnotice>
<title>crypto</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2000-06-20</date>
- <rev>B</rev>
</header>
<module>crypto</module>
<modulesummary>Crypto Functions</modulesummary>
<description>
<p>This module provides a set of cryptographic functions.
</p>
- <p>References:</p>
<list type="bulleted">
<item>
- <p>md4: The MD4 Message Digest Algorithm (RFC 1320)</p>
- </item>
- <item>
- <p>md5: The MD5 Message Digest Algorithm (RFC 1321)</p>
- </item>
- <item>
- <p>sha: Secure Hash Standard (FIPS 180-2)</p>
- </item>
- <item>
- <p>hmac: Keyed-Hashing for Message Authentication (RFC 2104)</p>
- </item>
- <item>
- <p>des: Data Encryption Standard (FIPS 46-3)</p>
+ <p>Hash functions -
+ <url href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf"> Secure Hash Standard</url>,
+ <url href="http://www.ietf.org/rfc/rfc1321.txt"> The MD5 Message Digest Algorithm (RFC 1321)</url> and
+ <url href="http://www.ietf.org/rfc/rfc1320.txt">The MD4 Message Digest Algorithm (RFC 1320)</url>
+ </p>
</item>
<item>
- <p>aes: Advanced Encryption Standard (AES) (FIPS 197) </p>
+ <p>Hmac functions - <url href="http://www.ietf.org/rfc/rfc2104.txt"> Keyed-Hashing for Message Authentication (RFC 2104) </url></p>
</item>
<item>
- <p>ecb, cbc, cfb, ofb, ctr: Recommendation for Block Cipher Modes
- of Operation (NIST SP 800-38A).</p>
+ <p>Block ciphers - <url href="http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html"> </url> DES and AES in
+ Block Cipher Modes - <url href="http://csrc.nist.gov/groups/ST/toolkit/BCM/index.html"> ECB, CBC, CFB, OFB and CTR </url></p>
</item>
<item>
- <p>rsa: Recommendation for Block Cipher Modes of Operation
- (NIST 800-38A)</p>
+ <p><url href="http://www.ietf.org/rfc/rfc1321.txt"> RSA encryption RFC 1321 </url> </p>
</item>
<item>
- <p>dss: Digital Signature Standard (FIPS 186-2)</p>
+ <p>Digital signatures <url href="http://csrc.nist.gov/publications/drafts/fips186-3/fips_186-3.pdf">Digital Signature Standard (DSS)</url> and<url href="http://csrc.nist.gov/groups/STM/cavp/documents/dss2/ecdsa2vs.pdf"> Elliptic Curve Digital
+ Signature Algorithm (ECDSA) </url> </p>
</item>
<item>
- <p>srp: Secure Remote Password Protocol (RFC 2945)</p>
+ <p><url href="http://www.ietf.org/rfc/rfc2945.txt"> Secure Remote Password Protocol (SRP - RFC 2945) </url></p>
</item>
-
-
</list>
- <p>The above publications can be found at <url href="http://csrc.nist.gov/publications">NIST publications</url>, at <url href="http://www.ietf.org">IETF</url>.
- </p>
- <p><em>Types</em></p>
- <pre>
-byte() = 0 ... 255
-ioelem() = byte() | binary() | iolist()
-iolist() = [ioelem()]
-Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
- </pre>
- <p></p>
</description>
+
+ <section>
+ <title>DATA TYPES </title>
+
+ <p><code>key_value() = integer() | binary() </code></p>
+ <p>Always <c>binary()</c> when used as return value</p>
+
+ <p><code>rsa_public() = [key_value()] = [E, N] </code></p>
+ <p> Where E is the public exponent and N is public modulus. </p>
+
+ <p><code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code></p>
+ <p>Where E is the public exponent, N is public modulus and D is
+ the private exponent.The longer key format contains redundant
+ information that will make the calculation faster. P1,P2 are first
+ and second prime factors. E1,E2 are first and second exponents. C
+ is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p>
+
+ <p><code>dss_public() = [key_value()] = [P, Q, G, Y] </code></p>
+ <p>Where P, Q and G are the dss parameters and Y is the public key.</p>
+
+ <p><code>dss_private() = [key_value()] = [P, Q, G, X] </code></p>
+ <p>Where P, Q and G are the dss parameters and X is the private key.</p>
+
+ <p><code>srp_public() = key_value() </code></p>
+ <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <p><code>srp_private() = key_value() </code></p>
+ <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is
+ <c>u</c> (optional will be generated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ Version = '3' | '6' | '6a'
+ </p>
+
+ <p><code>dh_public() = key_value() </code></p>
+
+ <p><code>dh_private() = key_value() </code></p>
+
+ <p><code>dh_params() = [key_value()] = [P, G] </code></p>
+
+ <p><code>ecdh_public() = key_value() </code></p>
+
+ <p><code>ecdh_private() = key_value() </code></p>
+
+ <p><code>ecdh_params() = ec_named_curve() |
+ {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(), CoFactor :: none | integer()} </code></p>
+
+ <p><code>ec_field() = {prime_field, Prime :: integer()} |
+ {characteristic_two_field, M :: integer(), Basis :: ec_basis()}</code></p>
+
+ <p><code>ec_basis() = {tpbasis, K :: non_neg_integer()} |
+ {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} |
+ onbasis</code></p>
+
+ <p><code>ec_named_curve() ->
+ sect571r1| sect571k1| sect409r1| sect409k1| secp521r1| secp384r1| secp224r1| secp224k1|
+ secp192k1| secp160r2| secp128r2| secp128r1| sect233r1| sect233k1| sect193r2| sect193r1|
+ sect131r2| sect131r1| sect283r1| sect283k1| sect163r2| secp256k1| secp160k1| secp160r1|
+ secp112r2| secp112r1| sect113r2| sect113r1| sect239k1| sect163r1| sect163k1| secp256r1|
+ secp192r1 </code></p>
+
+ <p><code>stream_cipher() = rc4 | aes_ctr </code></p>
+
+ <p><code>block_cipher() = aes_cbc128 | aes_cfb128 | blowfish_cbc |
+ blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cbf
+ | des_ede3 | rc2_cbc </code></p>
+
+ <p><code>stream_key() = aes_key() | rc4_key() </code></p>
+
+ <p><code>block_key() = aes_key() | blowfish_key() | des_key()| des3_key() </code></p>
+
+ <p><code>aes_key() = iodata() </code> Key length is 128, 192 or 256 bits</p>
+
+ <p><code>rc4_key() = iodata() </code> Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)</p>
+
+ <p><code>blowfish_key() = iodata() </code> Variable key length from 32 bits up to 448 bits</p>
+
+ <p><code>des_key() = iodata() </code> Key length is 64 bits (in CBC mode only 8 bits are used)</p>
+
+ <p><code>des3_key() = [binary(), binary(), binary()] </code> Each key part is 64 bits (in CBC mode only 8 bits are used)</p>
+
+ <p><code>digest_type() = md5 | sha | sha224 | sha256 | sha384 | sha512</code></p>
+
+ <p><code> hash_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> md4 is also supported for hash_init/1 and hash/2.
+ Note that both md4 and md5 are recommended only for compatibility with existing applications.
+ </p>
+ <p><code> cipher_algorithms() = des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 |
+ blowfish_cbc | blowfish_cfb64 | aes_cbc128 | aes_cfb128| aes_cbc256 | rc2_cbc | aes_ctr| rc4 </code> </p>
+ <p><code> public_key_algorithms() = rsa |dss | ecdsa | dh | ecdh </code> </p>
+
+ </section>
+
<funcs>
- <func>
- <name>start() -> ok</name>
- <fsummary>Start the crypto server.</fsummary>
- <desc>
- <p>Starts the crypto server.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> ok</name>
- <fsummary>Stop the crypto server.</fsummary>
- <desc>
- <p>Stops the crypto server.</p>
- </desc>
- </func>
- <func>
- <name>info() -> [atom()]</name>
- <fsummary>Provide a list of available crypto functions.</fsummary>
- <desc>
- <p>Provides the available crypto functions in terms of a list
- of atoms.</p>
- </desc>
- </func>
- <func>
- <name>algorithms() -> [atom()]</name>
- <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>
+ <func>
+ <name>block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name>
+ <fsummary>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Name = binary()</v>
- <v>VerNum = integer()</v>
- <v>VerStr = binary()</v>
+ <v>Type = block_cipher() </v>
+ <v>Key = block_key() </v>
+ <v>PlainText = iodata() </v>
+ <v>IVec = CipherText = binary()</v>
</type>
<desc>
- <p>Provides the name and version of the libraries used by crypto.</p>
- <p><c>Name</c> is the name of the library. <c>VerNum</c> is
- the numeric version according to the library's own versioning
- scheme. <c>VerStr</c> contains a text variant of the version.</p>
- <pre>
-> <input>info_lib().</input>
-[{&lt;&lt;"OpenSSL"&gt;&gt;,9469983,&lt;&lt;"OpenSSL 0.9.8a 11 Oct 2005"&gt;&gt;}]
- </pre>
- <note><p>
- From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
- <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
- The text variant represents the OpenSSL library used at runtime.
- In earlier OTP versions both numeric and text was taken from the library.
- </p></note>
- </desc>
- </func>
- <func>
- <name>md4(Data) -> Digest</name>
- <fsummary>Compute an <c>MD4</c>message digest from <c>Data</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD4</c> message digest from <c>Data</c>, where
- the length of the digest is 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>md4_init() -> Context</name>
- <fsummary>Creates an MD4 context</fsummary>
- <type>
- <v>Context = binary()</v>
- </type>
- <desc>
- <p>Creates an MD4 context, to be used in subsequent calls to
- <c>md4_update/2</c>.</p>
- </desc>
- </func>
- <func>
- <name>md4_update(Context, Data) -> NewContext</name>
- <fsummary>Update an MD4 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
- </type>
- <desc>
- <p>Updates an MD4 <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
- </desc>
- </func>
- <func>
- <name>md4_final(Context) -> Digest</name>
- <fsummary>Finish the update of an MD4 <c>Context</c>and return the computed <c>MD4</c>message digest</fsummary>
- <type>
- <v>Context = Digest = binary()</v>
- </type>
- <desc>
- <p>Finishes the update of an MD4 <c>Context</c> and returns
- the computed <c>MD4</c> message digest.</p>
- </desc>
- </func>
- <func>
- <name>md5(Data) -> Digest</name>
- <fsummary>Compute an <c>MD5</c>message digest from <c>Data</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5</c> message digest from <c>Data</c>, where
- the length of the digest is 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>md5_init() -> Context</name>
- <fsummary>Creates an MD5 context</fsummary>
- <type>
- <v>Context = binary()</v>
- </type>
- <desc>
- <p>Creates an MD5 context, to be used in subsequent calls to
- <c>md5_update/2</c>.</p>
- </desc>
- </func>
- <func>
- <name>md5_update(Context, Data) -> NewContext</name>
- <fsummary>Update an MD5 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
- </type>
- <desc>
- <p>Updates an MD5 <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
+ <p>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.
+ </p>
</desc>
</func>
+
<func>
- <name>md5_final(Context) -> Digest</name>
- <fsummary>Finish the update of an MD5 <c>Context</c>and return the computed <c>MD5</c>message digest</fsummary>
+ <name>block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name>
+ <fsummary>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Context = Digest = binary()</v>
+ <v>Type = block_cipher() </v>
+ <v>Key = block_key() </v>
+ <v>PlainText = iodata() </v>
+ <v>IVec = CipherText = binary()</v>
</type>
<desc>
- <p>Finishes the update of an MD5 <c>Context</c> and returns
- the computed <c>MD5</c> message digest.</p>
+ <p>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.
+ </p>
</desc>
</func>
- <func>
- <name>sha(Data) -> Digest</name>
- <fsummary>Compute an <c>SHA</c>message digest from <c>Data</c></fsummary>
+
+ <func>
+ <name>bytes_to_integer(Bin) -> Integer </name>
+ <fsummary>Convert binary representation, of an integer, to an Erlang integer.</fsummary>
<type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
+ <v>Bin = binary() - as returned by crypto functions</v>
+
+ <v>Integer = integer() </v>
</type>
<desc>
- <p>Computes an <c>SHA</c> message digest from <c>Data</c>, where
- the length of the digest is 160 bits (20 bytes).</p>
+ <p>Convert binary representation, of an integer, to an Erlang integer.
+ </p>
</desc>
</func>
+
<func>
- <name>sha_init() -> Context</name>
- <fsummary>Create an SHA context</fsummary>
+ <name>compute_key(Type, OthersPublicKey, MyKey, Params) -> SharedSecret</name>
+ <fsummary>Computes the shared secret</fsummary>
<type>
- <v>Context = binary()</v>
+ <v> Type = dh | ecdh | srp </v>
+ <v>OthersPublicKey = dh_public() | ecdh_public() | srp_public() </v>
+ <v>MyKey = dh_private() | ecdh_private() | {srp_public(),srp_private()}</v>
+ <v>Params = dh_params() | ecdh_params() | SrpUserParams | SrpHostParams</v>
+ <v>SrpUserParams = {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]} </v>
+ <v>SrpHostParams = {host, [Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]} </v>
+ <v>SharedSecret = binary()</v>
</type>
<desc>
- <p>Creates an SHA context, to be used in subsequent calls to
- <c>sha_update/2</c>.</p>
+ <p>Computes the shared secret from the private key and the other party's public key.
+ See also <seealso marker="public_key:public_key#compute_key/2">public_key:compute_key/2</seealso>
+ </p>
</desc>
</func>
+
<func>
- <name>sha_update(Context, Data) -> NewContext</name>
- <fsummary>Update an SHA context</fsummary>
+ <name>exor(Data1, Data2) -> Result</name>
+ <fsummary>XOR data</fsummary>
<type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
+ <v>Data1, Data2 = iodata()</v>
+ <v>Result = binary()</v>
</type>
<desc>
- <p>Updates an SHA <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
+ <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
</desc>
</func>
- <func>
- <name>sha_final(Context) -> Digest</name>
- <fsummary>Finish the update of an SHA context</fsummary>
- <type>
- <v>Context = Digest = binary()</v>
- </type>
- <desc>
- <p>Finishes the update of an SHA <c>Context</c> and returns
- the computed <c>SHA</c> message digest.</p>
+
+ <func>
+ <name>generate_key(Type, Params) -> {PublicKey, PrivKeyOut} </name>
+ <name>generate_key(Type, Params, PrivKeyIn) -> {PublicKey, PrivKeyOut} </name>
+ <fsummary>Generates a public keys of type <c>Type</c></fsummary>
+ <type>
+ <v> Type = dh | ecdh | srp </v>
+ <v>Params = dh_params() | ecdh_params() | SrpUserParams | SrpHostParams </v>
+ <v>SrpUserParams = {user, [Generator::binary(), Prime::binary(), Version::atom()]}</v>
+ <v>SrpHostParams = {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}</v>
+ <v>PublicKey = dh_public() | ecdh_public() | srp_public() </v>
+ <v>PrivKeyIn = undefined | dh_private() | srp_private() </v>
+ <v>PrivKeyOut = dh_private() | ecdh_private() | srp_private() </v>
+ </type>
+ <desc>
+ <p>Generates public keys of type <c>Type</c>.
+ See also <seealso marker="public_key:public_key#generate_key/1">public_key:generate_key/1</seealso>
+ </p>
</desc>
</func>
- <func>
+
+ <func>
<name>hash(Type, Data) -> Digest</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | message_digest_algorithms()</v>
<v>Data = iodata()</v>
<v>Digest = binary()</v>
</type>
@@ -288,11 +259,12 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
+
<func>
<name>hash_init(Type) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | message_digest_algorithms()</v>
</type>
<desc>
<p>Initializes the context for streaming hash operations. <c>Type</c> determines
@@ -302,6 +274,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
+
<func>
<name>hash_update(Context, Data) -> NewContext</name>
<fsummary></fsummary>
@@ -329,38 +302,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
function used to generate it.</p>
</desc>
</func>
- <func>
- <name>md5_mac(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5 MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the the length of the
- Mac is 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>md5_mac_96(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5 MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the length of the Mac
- is 96 bits (12 bytes).</p>
- </desc>
- </func>
+
<func>
<name>hmac(Type, Key, Data) -> Mac</name>
<name>hmac(Type, Key, Data, MacLength) -> Mac</name>
<fsummary></fsummary>
<type>
- <v>Type = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = message_digest_algorithms() </v>
<v>Key = iodata()</v>
<v>Data = iodata()</v>
<v>MacLength = integer()</v>
@@ -372,12 +320,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
will limit the size of the resultant <c>Mac</c>.
</desc>
</func>
+
<func>
<name>hmac_init(Type, Key) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
- <v>Key = iolist() | binary()</v>
+ <v>Type = message_digest_algorithms()</v>
+ <v>Key = iodata()</v>
<v>Context = binary()</v>
</type>
<desc>
@@ -386,20 +335,26 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
key. The key can be any length.</p>
</desc>
</func>
+
<func>
<name>hmac_update(Context, Data) -> NewContext</name>
<fsummary></fsummary>
<type>
<v>Context = NewContext = binary()</v>
- <v>Data = iolist() | binary()</v>
+ <v>Data = iodata()</v>
</type>
<desc>
<p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
must have been generated using an HMAC init function (such as
<seealso marker="#hmac_init/2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c>
- must be passed into the next call to <c>hmac_update</c>.</p>
+ must be passed into the next call to <c>hmac_update</c>
+ or to one of the functions <seealso marker="#hmac_final/1">hmac_final</seealso> and
+ <seealso marker="#hmac_final_n/1">hmac_final_n</seealso>
+ </p>
+
</desc>
</func>
+
<func>
<name>hmac_final(Context) -> Mac</name>
<fsummary></fsummary>
@@ -411,6 +366,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
determined by the type of hash function used to generate it.</p>
</desc>
</func>
+
<func>
<name>hmac_final_n(Context, HashLen) -> Mac</name>
<fsummary></fsummary>
@@ -423,1024 +379,404 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
zero. <c>Mac</c> will be a binary with at most <c>HashLen</c> bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than <c>HashLen</c> bytes.</p>
</desc>
</func>
- <func>
- <name>sha_mac(Key, Data) -> Mac</name>
- <name>sha_mac(Key, Data, MacLength) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- <v>MacLenength = integer() =&lt; 20 </v>
- </type>
- <desc>
- <p>Computes an <c>SHA MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the default length of the Mac
- is 160 bits (20 bytes).</p>
- </desc>
- </func>
- <func>
- <name>sha_mac_96(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>SHA MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>SHA MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the length of the Mac
- is 96 bits (12 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in CBC
- mode. <c>Text</c> must be a multiple of 64 bits (8
- bytes). <c>Key</c> is the DES key, and <c>IVec</c> is an
- arbitrary initializing vector. The lengths of <c>Key</c> and
- <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in CBC mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in CBC mode.
- <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. <c>Cipher</c>
- must be a multiple of 64 bits (8 bytes). The lengths of
- <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_ivec(Data) -> IVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>des_cbc_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>IVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>des_cbc_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in CFB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in 8-bit CFB
- mode. <c>Key</c> is the DES key, and <c>IVec</c> is an
- arbitrary initializing vector. The lengths of <c>Key</c> and
- <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in CFB mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in 8-bit CFB mode.
- <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. The lengths of
- <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_ivec(IVec, Data) -> NextIVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>des_cfb_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>IVec = iolist() | binary()</v>
- <v>Data = iolist() | binary()</v>
- <v>NextIVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>des_cfb_[encrypt|decrypt]</c>. <c>IVec</c> is the vector
- used in the previous iteration step. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>des3_cbc_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES3 in CBC mode</fsummary>
- <type>
- <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES3 in CBC
- mode. <c>Text</c> must be a multiple of 64 bits (8
- bytes). <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES
- keys, and <c>IVec</c> is an arbitrary initializing
- vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES3 in CBC mode</fsummary>
- <type>
- <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES3 in CBC mode.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and
- <c>IVec</c> is an arbitrary initializing vector.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must
- and <c>IVec</c> must have the same values as those used when
- encrypting. <c>Cipher</c> must be a multiple of 64 bits (8
- bytes). The lengths of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des3_cfb_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES3 in CFB mode</fsummary>
- <type>
- <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES3 in 8-bit CFB
- mode. <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES
- keys, and <c>IVec</c> is an arbitrary initializing
- vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- <p>May throw exception <c>notsup</c> for old OpenSSL
- versions (0.9.7) that does not support this encryption mode.</p>
- </desc>
- </func>
- <func>
- <name>des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES3 in CFB mode</fsummary>
- <type>
- <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES3 in 8-bit CFB mode.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and
- <c>IVec</c> is an arbitrary initializing vector.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must
- and <c>IVec</c> must have the same values as those used when
- encrypting. The lengths of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
- <p>May throw exception <c>notsup</c> for old OpenSSL
- versions (0.9.7) that does not support this encryption mode.</p>
- </desc>
- </func>
-
- <func>
- <name>des_ecb_encrypt(Key, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in ECB mode.
- <c>Key</c> is the DES key. The lengths of <c>Key</c> and
- <c>Text</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_ecb_decrypt(Key, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in ECB mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in ECB mode.
- <c>Key</c> is the DES key. The lengths of <c>Key</c> and
- <c>Cipher</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
<func>
- <name>blowfish_ecb_encrypt(Key, Text) -> Cipher</name>
- <fsummary>Encrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_ecb_decrypt(Key, Text) -> Cipher</name>
- <fsummary>Decrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
+ <name>info_lib() -> [{Name,VerNum,VerStr}]</name>
+ <fsummary>Provides information about the libraries used by crypto.</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
+ <v>Name = binary()</v>
+ <v>VerNum = integer()</v>
+ <v>VerStr = binary()</v>
</type>
<desc>
- <p>Decrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
+ <p>Provides the name and version of the libraries used by crypto.</p>
+ <p><c>Name</c> is the name of the library. <c>VerNum</c> is
+ the numeric version according to the library's own versioning
+ scheme. <c>VerStr</c> contains a text variant of the version.</p>
+ <pre>
+> <input>info_lib().</input>
+[{&lt;&lt;"OpenSSL"&gt;&gt;,9469983,&lt;&lt;"OpenSSL 0.9.8a 11 Oct 2005"&gt;&gt;}]
+ </pre>
+ <note><p>
+ From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
+ <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
+ The text variant represents the OpenSSL library used at runtime.
+ In earlier OTP versions both numeric and text was taken from the library.
+ </p></note>
</desc>
</func>
<func>
- <name>blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple of 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Decrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
+ <name>mod_pow(N, P, M) -> Result</name>
+ <fsummary>Computes the function: N^P mod M</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
+ <v>N, P, M = binary() | integer()</v>
+ <v>Result = binary() | error</v>
</type>
<desc>
- <p>Decrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple 64 bits (8 bytes).</p>
+ <p>Computes the function <c>N^P mod M</c>.</p>
</desc>
</func>
<func>
- <name>blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>using Blowfish in CFB mode with 64
- bit feedback</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> using Blowfish in CFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_cfb64_decrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Decrypt <c>Text</c>using Blowfish in CFB mode with 64
- bit feedback</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Text</c> using Blowfish in CFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
- </desc>
+ <name>next_iv(Type, Data) -> NextIVec</name>
+ <name>next_iv(Type, Data, IVec) -> NextIVec</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Type = des_cbc | des3_cbc | aes_cbc | des_cfb</v>
+ <v>Data = iodata()</v>
+ <v>IVec = NextIVec = binary()</v>
+ </type>
+ <desc>
+ <p>Returns the initialization vector to be used in the next
+ iteration of encrypt/decrypt of type <c>Type</c>. <c>Data</c> is the
+ encrypted data from the previous iteration step. The <c>IVec</c>
+ argument is only needed for <c>des_cfb</c> as the vector used
+ in the previous iteration step.</p>
+ </desc>
</func>
<func>
- <name>blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>using Blowfish in OFB mode with 64
- bit feedback</fsummary>
+ <name>private_decrypt(Type, ChipherText, PrivateKey, Padding) -> PlainText</name>
+ <fsummary>Decrypts ChipherText using the private Key.</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
+ <v>Type = rsa</v>
+ <v>ChipherText = binary()</v>
+ <v>PrivateKey = rsa_private()</v>
+ <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
+ <v>PlainText = binary()</v>
</type>
<desc>
- <p>Encrypts <c>Text</c> using Blowfish in OFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
+ <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with
+ <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>)
+ using the <c>PrivateKey</c> and returns the
+ message. The <c>Padding</c> is the padding mode that was
+ used to encrypt the data,
+ see <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>.
+ See also <seealso marker="public_key:public_key#decrypt_private/2">public_key:decrypt_private/[2,3]</seealso>
+ </p>
</desc>
</func>
<func>
- <name>aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Cipher Feedback mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Cipher Feedback
- mode (CFB). <c>Key</c> is the
- AES key, and <c>IVec</c> is an arbitrary initializing vector.
- The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cfb_128_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Feedback mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Cipher Feedback Mode (CFB).
- <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. The lengths of
- <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Cipher Block Chaining mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Cipher Block Chaining
- mode (CBC). <c>Text</c>
- must be a multiple of 128 bits (16 bytes). <c>Key</c> is the
- AES key, and <c>IVec</c> is an arbitrary initializing vector.
- The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_128_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Block Chaining mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Cipher Block
- Chaining mode (CBC).
- <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. <c>Cipher</c>
- must be a multiple of 128 bits (16 bytes). The lengths of
- <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_ivec(Data) -> IVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>aes_cbc_*_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>IVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>aes_cbc_*_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Counter mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). <c>Text</c>
- can be any number of bytes. <c>Key</c> is the AES key and must be either
- 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Counter mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). <c>Cipher</c>
- can be any number of bytes. <c>Key</c> is the AES key and must be either
- 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_init(Key, IVec) -> State</name>
- <fsummary></fsummary>
- <type>
- <v>State = { K, I, E, C }</v>
- <v>Key = K = iolist()</v>
- <v>IVec = I = E = binary()</v>
- <v>C = integer()</v>
- </type>
- <desc>
- <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
- <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is
- an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
- <seealso marker="#aes_ctr_stream_encrypt/2">aes_ctr_stream_encrypt</seealso> and
- <seealso marker="#aes_ctr_stream_decrypt/2">aes_ctr_stream_decrypt</seealso>.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_encrypt(State, Text) -> { NewState, Cipher}</name>
- <fsummary></fsummary>
- <type>
- <v>Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). This function can be
- used to encrypt a stream of text using a series of calls instead of requiring all
- text to be in memory. <c>Text</c> can be any number of bytes. State is initialized using
- <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming
- encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>.
- <c>Cipher</c> is the encrypted cipher text.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_decrypt(State, Cipher) -> { NewState, Text }</name>
- <fsummary></fsummary>
- <type>
- <v>Cipher = iolist() | binary()</v>
- <v>Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). This function can be
- used to decrypt a stream of ciphertext using a series of calls instead of requiring all
- ciphertext to be in memory. <c>Cipher</c> can be any number of bytes. State is initialized using
- <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming
- encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>.
- <c>Text</c> is the decrypted data.</p>
- </desc>
- </func>
- <func>
- <name>erlint(Mpint) -> N</name>
- <name>mpint(N) -> Mpint</name>
- <fsummary>Convert between binary multi-precision integer and erlang big integer</fsummary>
- <type>
- <v>Mpint = binary()</v>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Convert a binary multi-precision integer <c>Mpint</c> to and from
- an erlang big integer. A multi-precision integer is a binary
- with the following form:
- <c><![CDATA[<<ByteLen:32/integer, Bytes:ByteLen/binary>>]]></c> where both
- <c>ByteLen</c> and <c>Bytes</c> are big-endian. Mpints are used in
- some of the functions in <c>crypto</c> and are not translated
- in the API for performance reasons.</p>
- </desc>
- </func>
- <func>
- <name>rand_bytes(N) -> binary()</name>
- <fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Generates N bytes randomly uniform 0..255, and returns the
- result in a binary. Uses the <c>crypto</c> library pseudo-random
- number generator.</p>
- </desc>
- </func>
- <func>
- <name>strong_rand_bytes(N) -> binary()</name>
- <fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Generates N bytes randomly uniform 0..255, and returns the
- result in a binary. Uses a cryptographically secure prng seeded and
- periodically mixed with operating system provided entropy. By default
- this is the <c>RAND_bytes</c> method from OpenSSL.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
- failed due to lack of secure "randomness".</p>
- </desc>
- </func>
- <func>
- <name>rand_uniform(Lo, Hi) -> N</name>
- <fsummary>Generate a random number</fsummary>
- <type>
- <v>Lo, Hi, N = Mpint | integer()</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the
- <c>crypto</c> library pseudo-random number generator. The
- arguments (and result) can be either erlang integers or binary
- multi-precision integers. <c>Hi</c> must be larger than <c>Lo</c>.</p>
- </desc>
- </func>
- <func>
- <name>strong_rand_mpint(N, Top, Bottom) -> Mpint</name>
- <fsummary>Generate an N bit random number</fsummary>
- <type>
- <v>N = non_neg_integer()</v>
- <v>Top = -1 | 0 | 1</v>
- <v>Bottom = 0 | 1</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Generate an N bit random number using OpenSSL's
- cryptographically strong pseudo random number generator
- <c>BN_rand</c>.</p>
- <p>The parameter <c>Top</c> places constraints on the most
- significant bits of the generated number. If <c>Top</c> is 1, then the
- two most significant bits will be set to 1, if <c>Top</c> is 0, the
- most significant bit will be 1, and if <c>Top</c> is -1 then no
- constraints are applied and thus the generated number may be less than
- N bits long.</p>
- <p>If <c>Bottom</c> is 1, then the generated number is
- constrained to be odd.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
- failed due to lack of secure "randomness".</p>
- </desc>
- </func>
- <func>
- <name>mod_exp(N, P, M) -> Result</name>
- <fsummary>Perform N ^ P mod M</fsummary>
- <type>
- <v>N, P, M, Result = Mpint</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>This function performs the exponentiation <c>N ^ P mod M</c>,
- using the <c>crypto</c> library.</p>
- </desc>
- </func>
- <func>
- <name>mod_exp_prime(N, P, M) -> Result</name>
- <fsummary>Computes the function: N^P mod M</fsummary>
+ <name>private_encrypt(Type, PlainText, PrivateKey, Padding) -> ChipherText</name>
+ <fsummary>Encrypts Msg using the private Key.</fsummary>
<type>
- <v>N, P, M = binary()</v>
- <v>Result = binary() | error</v>
+ <v>Type = rsa</v>
+ <v>PlainText = binary()</v>
+ <v>PrivateKey = rsa_private()</v>
+ <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
+ <v>ChipherText = binary()</v>
</type>
<desc>
- <p>Computes the function <c>N^P mod M</c>.</p>
+ <p>Encrypts the <c>PlainText</c> using the <c>PrivateKey</c>
+ and returns the cipher. The <c>Padding</c> decides what padding mode is used,
+ <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
+ used mode.
+ The size of the <c>Msg</c> must be less than <c>byte_size(N)-11</c> if
+ <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
+ is used.
+ See also <seealso marker="public_key:public_key#encrypt_private/2">public_key:encrypt_private/[2,3]</seealso>
+ </p>
</desc>
</func>
<func>
- <name>rsa_sign(DataOrDigest, Key) -> Signature</name>
- <name>rsa_sign(DigestType, DataOrDigest, Key) -> Signature</name>
- <fsummary>Sign the data using rsa with the given key.</fsummary>
+ <name>public_decrypt(Type, ChipherText, PublicKey, Padding) -> PlainText</name>
+ <fsummary>Decrypts ChipherText using the public Key.</fsummary>
<type>
- <v>DataOrDigest = Data | {digest,Digest}</v>
- <v>Data = Mpint</v>
- <v>Digest = binary()</v>
- <v>Key = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
- <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
- <d>The default <c>DigestType</c> is sha.</d>
- <v>Mpint = binary()</v>
- <v>Signature = binary()</v>
+ <v>Type = rsa</v>
+ <v>ChipherText = binary()</v>
+ <v>PublicKey = rsa_public() </v>
+ <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
+ <v>PlainText = binary()</v>
</type>
<desc>
- <p>Creates a RSA signature with the private key <c>Key</c>
- of a digest. The digest is either calculated as a
- <c>DigestType</c> digest of <c>Data</c> or a precalculated
- binary <c>Digest</c>.</p>
+ <p>Decrypts the <c>ChipherText</c> (encrypted with
+ <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>)
+ using the <c>PrivateKey</c> and returns the
+ message. The <c>Padding</c> is the padding mode that was
+ used to encrypt the data,
+ see <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>.
+ See also <seealso marker="public_key:public_key#decrypt_public/2">public_key:decrypt_public/[2,3]</seealso>
+ </p>
</desc>
</func>
<func>
- <name>rsa_verify(DataOrDigest, Signature, Key) -> Verified</name>
- <name>rsa_verify(DigestType, DataOrDigest, Signature, Key) -> Verified </name>
- <fsummary>Verify the digest and signature using rsa with given public key.</fsummary>
- <type>
- <v>Verified = boolean()</v>
- <v>DataOrDigest = Data | {digest|Digest}</v>
- <v>Data, Signature = Mpint</v>
- <v>Digest = binary()</v>
- <v>Key = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d>
- <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
- <d>The default <c>DigestType</c> is sha.</d>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Verifies that a digest matches the RSA signature using the
- signer's public key <c>Key</c>.
- The digest is either calculated as a <c>DigestType</c>
- digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>DigestType</c>
- is not supported by the underlying OpenSSL implementation.</p>
- </desc>
- </func>
-
- <func>
- <name>rsa_public_encrypt(PlainText, PublicKey, Padding) -> ChipherText</name>
+ <name>public_encrypt(Type, PlainText, PublicKey, Padding) -> ChipherText</name>
<fsummary>Encrypts Msg using the public Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>PlainText = binary()</v>
- <v>PublicKey = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d>
+ <v>PublicKey = rsa_public()</v>
<v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
<v>ChipherText = binary()</v>
</type>
<desc>
<p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c>
- and returns the cipher. The <c>Padding</c> decides what padding mode is used,
+ and returns the <c>CipherText</c>. The <c>Padding</c> decides what padding mode is used,
<c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
parameter. This mode is recommended for all new applications.
The size of the <c>Msg</c> must be less
than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
- <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
+ <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
+ <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
is used.
- Where byte_size(N) is the size part of an <c>Mpint-1</c>.
+ See also <seealso marker="public_key:public_key#encrypt_public/2">public_key:encrypt_public/[2,3]</seealso>
</p>
</desc>
</func>
<func>
- <name>rsa_private_decrypt(ChipherText, PrivateKey, Padding) -> PlainText</name>
- <fsummary>Decrypts ChipherText using the private Key.</fsummary>
- <type>
- <v>ChipherText = binary()</v>
- <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
- <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
- <v>PlainText = binary()</v>
- </type>
- <desc>
- <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with
- <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>)
- using the <c>PrivateKey</c> and returns the
- message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>.
- </p>
- </desc>
- </func>
- <func>
- <name>rsa_private_encrypt(PlainText, PrivateKey, Padding) -> ChipherText</name>
- <fsummary>Encrypts Msg using the private Key.</fsummary>
+ <name>rand_bytes(N) -> binary()</name>
+ <fsummary>Generate a binary of random bytes</fsummary>
<type>
- <v>PlainText = binary()</v>
- <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
- <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
- <v>ChipherText = binary()</v>
+ <v>N = integer()</v>
</type>
<desc>
- <p>Encrypts the <c>PlainText</c> using the <c>PrivateKey</c>
- and returns the cipher. The <c>Padding</c> decides what padding mode is used,
- <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
- used mode.
- The size of the <c>Msg</c> must be less than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used. Where byte_size(N) is the size part of an <c>Mpint-1</c>.
- </p>
+ <p>Generates N bytes randomly uniform 0..255, and returns the
+ result in a binary. Uses the <c>crypto</c> library pseudo-random
+ number generator.</p>
</desc>
</func>
- <func>
- <name>rsa_public_decrypt(ChipherText, PublicKey, Padding) -> PlainText</name>
- <fsummary>Decrypts ChipherText using the public Key.</fsummary>
+ <func>
+ <name>rand_uniform(Lo, Hi) -> N</name>
+ <fsummary>Generate a random number</fsummary>
<type>
- <v>ChipherText = binary()</v>
- <v>PublicKey = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus</d>
- <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
- <v>PlainText = binary()</v>
+ <v>Lo, Hi, N = integer()</v>
</type>
<desc>
- <p>Decrypts the <c>ChipherText</c> (encrypted with
- <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>)
- using the <c>PrivateKey</c> and returns the
- message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>.
- </p>
+ <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the
+ <c>crypto</c> library pseudo-random number generator.
+ <c>Hi</c> must be larger than <c>Lo</c>.</p>
</desc>
</func>
-
+
<func>
- <name>dss_sign(DataOrDigest, Key) -> Signature</name>
- <name>dss_sign(DigestType, DataOrDigest, Key) -> Signature</name>
- <fsummary>Sign the data using dsa with given private key.</fsummary>
+ <name>sign(Algorithm, DigestType, Msg, Key) -> binary()</name>
+ <fsummary> Create digital signature.</fsummary>
<type>
- <v>DigestType = sha</v>
- <v>DataOrDigest = Mpint | {digest,Digest}</v>
- <v>Key = [P, Q, G, X]</v>
- <v>P, Q, G, X = Mpint</v>
- <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss
- parameters and <c>X</c> is the private key.</d>
- <v>Digest = binary() with length 20 bytes</v>
- <v>Signature = binary()</v>
+ <v>Algorithm = rsa | dss | ecdsa </v>
+ <v>Msg = binary() | {digest,binary()}</v>
+ <d>The msg is either the binary "plain text" data to be
+ signed or it is the hashed value of "plain text" i.e. the
+ digest.</d>
+ <v>DigestType = digest_type()</v>
+ <v>Key = rsa_private() | dss_private() | [ecdh_private(),ecdh_params()]</v>
</type>
<desc>
- <p>Creates a DSS signature with the private key <c>Key</c> of
- a digest. The digest is either calculated as a SHA1
- digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p>
- <p>A deprecated feature is having <c>DigestType = 'none'</c>
- in which case <c>DataOrDigest</c> is a precalculated SHA1
- digest.</p>
+ <p>Creates a digital signature.</p>
+ <p>Algorithm <c>dss</c> can only be used together with digest type
+ <c>sha</c>.</p>
+ See also <seealso marker="public_key:public_key#sign/3">public_key:sign/3</seealso>
</desc>
</func>
<func>
- <name>dss_verify(DataOrDigest, Signature, Key) -> Verified</name>
- <name>dss_verify(DigestType, DataOrDigest, Signature, Key) -> Verified</name>
- <fsummary>Verify the data and signature using dsa with given public key.</fsummary>
- <type>
- <v>Verified = boolean()</v>
- <v>DigestType = sha</v>
- <v>DataOrDigest = Mpint | {digest,Digest}</v>
- <v>Data = Mpint | ShaDigest</v>
- <v>Signature = Mpint</v>
- <v>Key = [P, Q, G, Y]</v>
- <v>P, Q, G, Y = Mpint</v>
- <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss
- parameters and <c>Y</c> is the public key.</d>
- <v>Digest = binary() with length 20 bytes</v>
- </type>
+ <name>start() -> ok</name>
+ <fsummary> Equivalent to application:start(crypto). </fsummary>
<desc>
- <p>Verifies that a digest matches the DSS signature using the
- public key <c>Key</c>. The digest is either calculated as a SHA1
- digest of <c>Data</c> or is a precalculated binary <c>Digest</c>.</p>
- <p>A deprecated feature is having <c>DigestType = 'none'</c>
- in which case <c>DataOrDigest</c> is a precalculated SHA1
- digest binary.</p>
+ <p> Equivalent to application:start(crypto).</p>
</desc>
</func>
-
<func>
- <name>rc2_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to RC2 in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Ivec = Cipher = binary()</v>
- </type>
+ <name>stop() -> ok</name>
+ <fsummary> Equivalent to application:stop(crypto).</fsummary>
<desc>
- <p>Encrypts <c>Text</c> according to RC2 in CBC mode.</p>
+ <p> Equivalent to application:stop(crypto).</p>
</desc>
</func>
<func>
- <name>rc2_cbc_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypts <c>Cipher</c>according to RC2 in CBC mode</fsummary>
+ <name>strong_rand_bytes(N) -> binary()</name>
+ <fsummary>Generate a binary of random bytes</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Ivec = Cipher = binary()</v>
+ <v>N = integer()</v>
</type>
<desc>
- <p>Decrypts <c>Cipher</c> according to RC2 in CBC mode.</p>
+ <p>Generates N bytes randomly uniform 0..255, and returns the
+ result in a binary. Uses a cryptographically secure prng seeded and
+ periodically mixed with operating system provided entropy. By default
+ this is the <c>RAND_bytes</c> method from OpenSSL.</p>
+ <p>May throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".</p>
</desc>
</func>
-
<func>
- <name>rc4_encrypt(Key, Data) -> Result</name>
- <fsummary>Encrypt data using RC4</fsummary>
+ <name>stream_init(Type, Key) -> State</name>
+ <fsummary></fsummary>
<type>
- <v>Key, Data = iolist() | binary()</v>
- <v>Result = binary()</v>
+ <v>Type = rc4 </v>
+ <v>State = opaque() </v>
+ <v>Key = iodata()</v>
</type>
<desc>
- <p>Encrypts the data with RC4 symmetric stream encryption.
- Since it is symmetric, the same function is used for
- decryption.</p>
+ <p>Initializes the state for use in RC4 stream encryption
+ <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt/2">stream_decrypt</seealso></p>
</desc>
</func>
- <func>
- <name>dh_generate_key(DHParams) -> {PublicKey,PrivateKey} </name>
- <name>dh_generate_key(PrivateKey, DHParams) -> {PublicKey,PrivateKey} </name>
- <fsummary>Generates a Diffie-Hellman public key</fsummary>
+ <func>
+ <name>stream_init(Type, Key, IVec) -> State</name>
+ <fsummary></fsummary>
<type>
- <v>DHParameters = [P, G]</v>
- <v>P, G = Mpint</v>
- <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d>
- <v>PublicKey, PrivateKey = Mpint()</v>
+ <v>Type = aes_ctr </v>
+ <v>State = opaque() </v>
+ <v>Key = iodata()</v>
+ <v>IVec = binary()</v>
</type>
<desc>
- <p>Generates a Diffie-Hellman <c>PublicKey</c> and <c>PrivateKey</c> (if not given).
- </p>
+ <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
+ <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is
+ an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
+ <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt/2">stream_decrypt</seealso>.</p>
</desc>
</func>
<func>
- <name>dh_compute_key(OthersPublicKey, MyPrivateKey, DHParams) -> SharedSecret</name>
- <fsummary>Computes the shared secret</fsummary>
+ <name>stream_encrypt(State, PlainText) -> { NewState, CipherText}</name>
+ <fsummary></fsummary>
<type>
- <v>DHParameters = [P, G]</v>
- <v>P, G = Mpint</v>
- <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d>
- <v>OthersPublicKey, MyPrivateKey = Mpint()</v>
- <v>SharedSecret = binary()</v>
+ <v>Text = iodata()</v>
+ <v>CipherText = binary()</v>
</type>
<desc>
- <p>Computes the shared secret from the private key and the other party's public key.
- </p>
+ <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init/2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
-
+
<func>
- <name>srp_generate_key(Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Verifier, Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Verifier, Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
- <fsummary>Generates SRP public keys</fsummary>
+ <name>stream_decrypt(State, CipherText) -> { NewState, PlainText }</name>
+ <fsummary></fsummary>
<type>
- <v>Verifier = binary()</v>
- <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Generator = binary() </v>
- <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Prime = binary() </v>
- <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Version = '3' | '6' | '6a' </v>
- <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
- <v>PublicKey = binary()</v>
- <d> Parameter A or B from <url href="http://srp.stanford.edu/design.html">SRP design</url></d>
- <v>Private = PrivateKey = binary() - generated if not supplied</v>
- <d>Parameter a or b from <url href="http://srp.stanford.edu/design.html">SRP design</url></d>
+ <v>CipherText = iodata()</v>
+ <v>PlainText = binary()</v>
</type>
<desc>
- <p>Generates SRP public keys for the client side (first argument is Generator)
- or for the server side (first argument is Verifier).</p>
+ <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init/2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
- <func>
- <name>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>
+ <func>
+ <name>supports() -> AlgorithmList </name>
+ <fsummary>Provide a list of available crypto algorithms.</fsummary>
<type>
- <v>DerivedKey = binary()</v>
- <d>Parameter x from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Verifier = binary()</v>
- <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Prime = binary() </v>
- <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Generator = binary() </v>
- <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ClientPublic = binary() </v>
- <d>Parameter A from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ClientPrivate = binary() </v>
- <d>Parameter a from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ServerPublic = binary() </v>
- <d>Parameter B from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ServerPrivate = binary() </v>
- <d>Parameter b from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Version = '3' | '6' | '6a' </v>
- <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
- <v>SessionKey = binary()</v>
- <d>Result K from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
+ <v> AlgorithmList = [{hashs, [hash_algorithms()]},
+ {ciphers, [cipher_algorithms()]},
+ {public_keys, [public_key_algorithms()]}
+ </v>
</type>
<desc>
- <p>
- Computes the SRP session key (shared secret) for the client side (first argument is DerivedKey)
- or for the server side (first argument is Verifier). Also used
- as premaster secret by TLS-SRP ciher suites.
- </p>
+ <p> Can be used to determine which crypto algorithms that are supported
+ by the underlying OpenSSL library</p>
</desc>
</func>
+
- <func>
- <name>exor(Data1, Data2) -> Result</name>
- <fsummary>XOR data</fsummary>
- <type>
- <v>Data1, Data2 = iolist() | binary()</v>
- <v>Result = binary()</v>
- </type>
- <desc>
- <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
+ <func>
+ <name>verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean()</name>
+ <fsummary>Verifies a digital signature.</fsummary>
+ <type>
+ <v> Algorithm = rsa | dss | ecdsa </v>
+ <v>Msg = binary() | {digest,binary()}</v>
+ <d>The msg is either the binary "plain text" data
+ or it is the hashed value of "plain text" i.e. the digest.</d>
+ <v>DigestType = digest_type()</v>
+ <v>Signature = binary()</v>
+ <v>Key = rsa_public() | dss_public() | [ecdh_public(),ecdh_params()]</v>
+ </type>
+ <desc>
+ <p>Verifies a digital signature</p>
+ <p>Algorithm <c>dss</c> can only be used together with digest type
+ <c>sha</c>.</p>
+
+ See also <seealso marker="public_key:public_key#sign/3">public_key:verify/3</seealso>
</desc>
</func>
- </funcs>
- <section>
- <title>DES in CBC mode</title>
- <p>The Data Encryption Standard (DES) defines an algorithm for
- encrypting and decrypting an 8 byte quantity using an 8 byte key
- (actually only 56 bits of the key is used).
- </p>
- <p>When it comes to encrypting and decrypting blocks that are
- multiples of 8 bytes various modes are defined (NIST SP
- 800-38A). One of those modes is the Cipher Block Chaining (CBC)
- mode, where the encryption of an 8 byte segment depend not only
- of the contents of the segment itself, but also on the result of
- encrypting the previous segment: the encryption of the previous
- segment becomes the initializing vector of the encryption of the
- current segment.
- </p>
- <p>Thus the encryption of every segment depends on the encryption
- key (which is secret) and the encryption of the previous
- segment, except the first segment which has to be provided with
- an initial initializing vector. That vector could be chosen at
- random, or be a counter of some kind. It does not have to be
- secret.
- </p>
- <p>The following example is drawn from the old FIPS 81 standard
- (replaced by NIST SP 800-38A), where both the plain text and the
- resulting cipher text is settled. The following code fragment
- returns `true'.
- </p>
- <pre><![CDATA[
-
- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>,
- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>,
- P = "Now is the time for all ",
- C = crypto:des_cbc_encrypt(Key, IVec, P),
- % Which is the same as
- P1 = "Now is t", P2 = "he time ", P3 = "for all ",
- C1 = crypto:des_cbc_encrypt(Key, IVec, P1),
- C2 = crypto:des_cbc_encrypt(Key, C1, P2),
- C3 = crypto:des_cbc_encrypt(Key, C2, P3),
-
- C = <<C1/binary, C2/binary, C3/binary>>,
- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c,
- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f,
- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>,
- <<"Now is the time for all ">> ==
- crypto:des_cbc_decrypt(Key, IVec, C).
- ]]></pre>
- <p>The following is true for the DES CBC mode. For all
- decompositions <c>P1 ++ P2 = P</c> of a plain text message
- <c>P</c> (where the length of all quantities are multiples of 8
- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++
- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with
- <c>Key</c> and the initializing vector <c>IVec</c>, and where
- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c>
- and the initializing vector <c>last8(C1)</c>,
- where <c>last(Binary)</c> denotes the last 8 bytes of the
- binary <c>Binary</c>.
- </p>
- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a
- cipher text message <c>C</c> (where the length of all quantities
- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c>
- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by
- decrypting <c>C1</c> with <c>Key</c> and the initializing vector
- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting
- <c>C2</c> with <c>Key</c> and the initializing vector
- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above.
- </p>
- <p>For DES3 (which uses three 64 bit keys) the situation is the
- same.
- </p>
- </section>
+ </funcs>
+
+ <!-- Maybe put this in the users guide -->
+ <!-- <section> -->
+ <!-- <title>DES in CBC mode</title> -->
+ <!-- <p>The Data Encryption Standard (DES) defines an algorithm for -->
+ <!-- encrypting and decrypting an 8 byte quantity using an 8 byte key -->
+ <!-- (actually only 56 bits of the key is used). -->
+ <!-- </p> -->
+ <!-- <p>When it comes to encrypting and decrypting blocks that are -->
+ <!-- multiples of 8 bytes various modes are defined (NIST SP -->
+ <!-- 800-38A). One of those modes is the Cipher Block Chaining (CBC) -->
+ <!-- mode, where the encryption of an 8 byte segment depend not only -->
+ <!-- of the contents of the segment itself, but also on the result of -->
+ <!-- encrypting the previous segment: the encryption of the previous -->
+ <!-- segment becomes the initializing vector of the encryption of the -->
+ <!-- current segment. -->
+ <!-- </p> -->
+ <!-- <p>Thus the encryption of every segment depends on the encryption -->
+ <!-- key (which is secret) and the encryption of the previous -->
+ <!-- segment, except the first segment which has to be provided with -->
+ <!-- an initial initializing vector. That vector could be chosen at -->
+ <!-- random, or be a counter of some kind. It does not have to be -->
+ <!-- secret. -->
+ <!-- </p> -->
+ <!-- <p>The following example is drawn from the old FIPS 81 standard -->
+ <!-- (replaced by NIST SP 800-38A), where both the plain text and the -->
+ <!-- resulting cipher text is settled. The following code fragment -->
+ <!-- returns `true'. -->
+ <!-- </p> -->
+ <!-- <pre><![CDATA[ -->
+
+ <!-- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>, -->
+ <!-- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>, -->
+ <!-- P = "Now is the time for all ", -->
+ <!-- C = crypto:des_cbc_encrypt(Key, IVec, P), -->
+ <!-- % Which is the same as -->
+ <!-- P1 = "Now is t", P2 = "he time ", P3 = "for all ", -->
+ <!-- C1 = crypto:des_cbc_encrypt(Key, IVec, P1), -->
+ <!-- C2 = crypto:des_cbc_encrypt(Key, C1, P2), -->
+ <!-- C3 = crypto:des_cbc_encrypt(Key, C2, P3), -->
+
+ <!-- C = <<C1/binary, C2/binary, C3/binary>>, -->
+ <!-- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c, -->
+ <!-- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f, -->
+ <!-- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>, -->
+ <!-- <<"Now is the time for all ">> == -->
+ <!-- crypto:des_cbc_decrypt(Key, IVec, C). -->
+ <!-- ]]></pre> -->
+ <!-- <p>The following is true for the DES CBC mode. For all -->
+ <!-- decompositions <c>P1 ++ P2 = P</c> of a plain text message -->
+ <!-- <c>P</c> (where the length of all quantities are multiples of 8 -->
+ <!-- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++ -->
+ <!-- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with -->
+ <!-- <c>Key</c> and the initializing vector <c>IVec</c>, and where -->
+ <!-- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c> -->
+ <!-- and the initializing vector <c>last8(C1)</c>, -->
+ <!-- where <c>last(Binary)</c> denotes the last 8 bytes of the -->
+ <!-- binary <c>Binary</c>. -->
+ <!-- </p> -->
+ <!-- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a -->
+ <!-- cipher text message <c>C</c> (where the length of all quantities -->
+ <!-- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c> -->
+ <!-- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by -->
+ <!-- decrypting <c>C1</c> with <c>Key</c> and the initializing vector -->
+ <!-- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting -->
+ <!-- <c>C2</c> with <c>Key</c> and the initializing vector -->
+ <!-- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above. -->
+ <!-- </p> -->
+ <!-- <p>For DES3 (which uses three 64 bit keys) the situation is the -->
+ <!-- same. -->
+ <!-- </p> -->
+ <!-- </section> -->
</erlref>
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml
index 8371db1ff2..6d26076c04 100644
--- a/lib/crypto/doc/src/crypto_app.xml
+++ b/lib/crypto/doc/src/crypto_app.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE appref SYSTEM "appref.dtd">
<appref>
@@ -24,81 +24,28 @@
</legalnotice>
<title>crypto</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <responsible>Peter H&ouml;gfeldt</responsible>
- <docno></docno>
- <approved>Peter H&ouml;gfeldt</approved>
- <checked>Peter H&ouml;gfeldt</checked>
- <date>2003-06-01</date>
- <rev>B</rev>
<file>crypto_app.sgml</file>
</header>
<app>crypto</app>
<appsummary>The Crypto Application</appsummary>
<description>
- <p>The purpose of the Crypto application is to provide message
- digest and DES encryption for SMNPv3. It provides computation of
- message digests MD5 and SHA, and CBC-DES encryption and
- decryption.</p>
- <p></p>
+ <p>The purpose of the Crypto application is to provide an Erlang API
+ to cryptographic functions, see <seealso marker="crypto">crypto(3)</seealso>.
+ Note that the API is on a fairly low level and there are some
+ corresponding API functions available in <seealso marker="public_key:public_key">public_key(3)</seealso>,
+ on a higher abstraction level, that uses the crypto application in its implementation.
+ </p>
</description>
<section>
- <title>Configuration</title>
- <p>The following environment configuration parameters are defined
- for the Crypto application. Refer to application(3) for more
- information about configuration parameters.
- </p>
- <taglist>
- <tag><c><![CDATA[debug = true | false <optional>]]></c></tag>
- <item>
- <p>Causes debug information to be written to standard
- error or standard output. Default is <c>false</c>.
- </p>
- </item>
- </taglist>
- </section>
+ <title>DEPENDENCIES</title>
- <section>
- <title>OpenSSL libraries</title>
- <p>The current implementation of the Erlang Crypto application is
- based on the <em>OpenSSL</em> package version 0.9.8 or higher.
- There are source and binary releases on the web.
- </p>
+ <p>The current crypto implementation uses nifs to interface OpenSSLs crypto library
+ and requires <em>OpenSSL</em> package version 0.9.8 or higher.</p>
<p>Source releases of OpenSSL can be downloaded from the <url href="http://www.openssl.org">OpenSSL</url> project home page,
- or mirror sites listed there.
- </p>
- <p>The same URL also contains links to some compiled binaries and
- libraries of OpenSSL (see the <c>Related/Binaries</c> menu) of
- which the <url href="http://www.shininglightpro.com/search.php?searchname=Win32+OpenSSL">Shining Light Productions Win32 and OpenSSL</url> pages are of
- interest for the Win32 user.
- </p>
- <p>For some Unix flavours there are binary packages available
- on the net.
- </p>
- <p>If you cannot find a suitable binary OpenSSL package, you
- have to fetch an OpenSSL source release and compile it.
- </p>
- <p>You then have to compile and install the library
- <c>libcrypto.so</c> (Unix), or the library <c>libeay32.dll</c>
- (Win32).
- </p>
- <p>For Unix The <c>crypto_drv</c> dynamic driver is delivered linked
- to OpenSSL libraries in <c>/usr/local/lib</c>, but the default
- dynamic linking will also accept libraries in <c>/lib</c> and
- <c>/usr/lib</c>.
- </p>
- <p>If that is not applicable to the particular Unix operating
- system used, the example <c>Makefile</c> in the Crypto
- <c>priv/obj</c> directory, should be used as a basis for
- relinking the final version of the port program.
- </p>
- <p>For <c>Win32</c> it is only required that the library can be
- found from the <c>PATH</c> environment variable, or that they
- reside in the appropriate <c>SYSTEM32</c> directory; hence no
- particular relinking is need. Hence no example <c>Makefile</c>
- for Win32 is provided.</p>
- </section>
+ or mirror sites listed there.
+ </p>
+ </section>
<section>
<title>SEE ALSO</title>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 1d0a9943c3..e042545094 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -21,104 +21,219 @@
-module(crypto).
--export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]).
+-export([start/0, stop/0, info_lib/0, supports/0, version/0, bytes_to_integer/1]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
+-export([sign/4, verify/5]).
+-export([generate_key/2, generate_key/3, compute_key/4]).
+-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-export([exor/2, strong_rand_bytes/1, mod_pow/3]).
+-export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
+-export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]).
+-export([next_iv/2, next_iv/3]).
+-export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]).
+-export([public_encrypt/4, private_decrypt/4]).
+-export([private_encrypt/4, public_decrypt/4]).
+-export([dh_generate_parameters/2, dh_check/1]). %% Testing see
+
+
+%% DEPRECATED
+%% Replaced by hash_*
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
-export([sha/1, sha_init/0, sha_update/2, sha_final/1]).
--export([sha224/1, sha224_init/0, sha224_update/2, sha224_final/1]).
--export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]).
--export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]).
--export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]).
+-deprecated({md4, 1, next_major_release}).
+-deprecated({md5, 1, next_major_release}).
+-deprecated({sha, 1, next_major_release}).
+-deprecated({md4_init, 0, next_major_release}).
+-deprecated({md5_init, 0, next_major_release}).
+-deprecated({sha_init, 0, next_major_release}).
+-deprecated({md4_update, 2, next_major_release}).
+-deprecated({md5_update, 2, next_major_release}).
+-deprecated({sha_update, 2, next_major_release}).
+-deprecated({md4_final, 1, next_major_release}).
+-deprecated({md5_final, 1, next_major_release}).
+-deprecated({sha_final, 1, next_major_release}).
+
+%% Replaced by hmac_*
-export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]).
--export([sha224_mac/2, sha224_mac/3]).
--export([sha256_mac/2, sha256_mac/3]).
--export([sha384_mac/2, sha384_mac/3]).
--export([sha512_mac/2, sha512_mac/3]).
--export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-deprecated({md5_mac, 2, next_major_release}).
+-deprecated({md5_mac_96, 2, next_major_release}).
+-deprecated({sha_mac, 2, next_major_release}).
+-deprecated({sha_mac, 3, next_major_release}).
+-deprecated({sha_mac_96, 2, next_major_release}).
+
+%% Replaced by sign/verify
+-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]).
+-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]).
+-deprecated({dss_verify, 3, next_major_release}).
+-deprecated({dss_verify, 4, next_major_release}).
+-deprecated({rsa_verify, 3, next_major_release}).
+-deprecated({rsa_verify, 4, next_major_release}).
+-deprecated({dss_sign, 2, next_major_release}).
+-deprecated({dss_sign, 3, next_major_release}).
+-deprecated({rsa_sign, 2, next_major_release}).
+-deprecated({rsa_sign, 3, next_major_release}).
+
+%% Replaced by generate_key
+-export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]).
+-deprecated({dh_generate_key, 1, next_major_release}).
+-deprecated({dh_generate_key, 2, next_major_release}).
+-deprecated({dh_compute_key, 3, next_major_release}).
+
+%% Replaced by mod_exp_prim and no longer needed
+-export([mod_exp/3, mpint/1, erlint/1, strong_rand_mpint/3]).
+-deprecated({mod_exp, 3, next_major_release}).
+-deprecated({mpint, 1, next_major_release}).
+-deprecated({erlint, 1, next_major_release}).
+-deprecated({strong_rand_mpint, 3, next_major_release}).
+
+%% Replaced by block_*
-export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]).
+-export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
-export([des_ecb_encrypt/2, des_ecb_decrypt/2]).
+-export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]).
-export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]).
--export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
-export([des3_cfb_encrypt/5, des3_cfb_decrypt/5]).
+-deprecated({des_cbc_encrypt, 3, next_major_release}).
+-deprecated({des_cbc_decrypt, 3, next_major_release}).
+-deprecated({des_cbc_ivec, 1, next_major_release}).
+-deprecated({des3_cbc_encrypt, 5, next_major_release}).
+-deprecated({des3_cbc_decrypt, 5, next_major_release}).
+-deprecated({des_ecb_encrypt, 2, next_major_release}).
+-deprecated({des_ecb_decrypt, 2, next_major_release}).
+-deprecated({des_ede3_cbc_encrypt, 5, next_major_release}).
+-deprecated({des_ede3_cbc_decrypt, 5, next_major_release}).
+-deprecated({des_cfb_encrypt, 3, next_major_release}).
+-deprecated({des_cfb_decrypt, 3, next_major_release}).
+-deprecated({des_cfb_ivec, 2, next_major_release}).
+-deprecated({des3_cfb_encrypt, 5, next_major_release}).
+-deprecated({des3_cfb_decrypt, 5, next_major_release}).
-export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]).
-export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]).
-export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]).
-export([blowfish_ofb64_encrypt/3]).
--export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]).
+-deprecated({blowfish_ecb_encrypt, 2, next_major_release}).
+-deprecated({blowfish_ecb_decrypt, 2, next_major_release}).
+-deprecated({blowfish_cbc_encrypt, 3, next_major_release}).
+-deprecated({blowfish_cbc_decrypt, 3, next_major_release}).
+-deprecated({blowfish_cfb64_encrypt, 3, next_major_release}).
+-deprecated({blowfish_cfb64_decrypt, 3, next_major_release}).
+-deprecated({blowfish_ofb64_encrypt, 3, next_major_release}).
-export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]).
--export([exor/2]).
--export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]).
--export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
--export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]).
--export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]).
--export([rsa_public_encrypt/3, rsa_private_decrypt/3]).
--export([rsa_private_encrypt/3, rsa_public_decrypt/3]).
--export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]).
--export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
--export([strong_rand_bytes/1, strong_rand_mpint/3]).
--export([mod_exp/3, mod_exp_prime/3, mpint/1, erlint/1]).
--export([srp_generate_key/4, srp_generate_key/3,
- srp_generate_key/5, srp_compute_key/6, srp_compute_key/7, srp_compute_key/8]).
-
-%% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]).
-export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]).
-export([aes_cbc_256_encrypt/3, aes_cbc_256_decrypt/3]).
-export([aes_cbc_ivec/1]).
--export([aes_ctr_encrypt/3, aes_ctr_decrypt/3]).
+-deprecated({aes_cfb_128_encrypt, 3, next_major_release}).
+-deprecated({aes_cfb_128_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_128_encrypt, 3, next_major_release}).
+-deprecated({aes_cbc_128_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_256_encrypt, 3, next_major_release}).
+-deprecated({aes_cbc_256_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_ivec, 1, next_major_release}).
+-export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3]).
+-export([rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
+-deprecated({rc2_cbc_encrypt, 3, next_major_release}).
+-deprecated({rc2_cbc_decrypt, 3, next_major_release}).
+%% allready replaced by above!
+-deprecated({rc2_40_cbc_encrypt, 3, next_major_release}).
+-deprecated({rc2_40_cbc_decrypt, 3, next_major_release}).
+
+%% Replaced by stream_*
-export([aes_ctr_stream_init/2, aes_ctr_stream_encrypt/2, aes_ctr_stream_decrypt/2]).
-
--export([dh_generate_parameters/2, dh_check/1]). %% Testing see below
-
-
--define(FUNC_LIST, [md4, md4_init, md4_update, md4_final,
+-export([rc4_set_key/1, rc4_encrypt_with_state/2]).
+-deprecated({aes_ctr_stream_init, 2, next_major_release}).
+-deprecated({aes_ctr_stream_encrypt, 2, next_major_release}).
+-deprecated({aes_ctr_stream_decrypt, 2, next_major_release}).
+-deprecated({rc4_set_key, 1, next_major_release}).
+-deprecated({rc4_encrypt_with_state, 2, next_major_release}).
+
+%% Not needed special case of stream_*
+-export([aes_ctr_encrypt/3, aes_ctr_decrypt/3, rc4_encrypt/2]).
+-deprecated({aes_ctr_encrypt, 3, next_major_release}).
+-deprecated({aes_ctr_decrypt, 3, next_major_release}).
+-deprecated({rc4_encrypt, 2, next_major_release}).
+
+%% Replace by public/private_encrypt/decrypt
+-export([rsa_public_encrypt/3, rsa_private_decrypt/3]).
+-export([rsa_private_encrypt/3, rsa_public_decrypt/3]).
+-deprecated({rsa_public_encrypt, 3, next_major_release}).
+-deprecated({rsa_private_decrypt, 3, next_major_release}).
+-deprecated({rsa_public_decrypt, 3, next_major_release}).
+-deprecated({rsa_private_encrypt, 3, next_major_release}).
+
+%% Replaced by crypto:module_info()
+-export([info/0]).
+-deprecated({info, 0, next_major_release}).
+
+-define(FUNC_LIST, [hash, hash_init, hash_update, hash_final,
+ hmac, hmac_init, hmac_update, hmac_final, hmac_final_n,
+ %% deprecated
+ md4, md4_init, md4_update, md4_final,
md5, md5_init, md5_update, md5_final,
sha, sha_init, sha_update, sha_final,
- sha224, sha224_init, sha224_update, sha224_final,
- sha256, sha256_init, sha256_update, sha256_final,
- sha384, sha384_init, sha384_update, sha384_final,
- sha512, sha512_init, sha512_update, sha512_final,
md5_mac, md5_mac_96,
sha_mac, sha_mac_96,
- sha224_mac, sha256_mac, sha384_mac, sha512_mac,
+ %%
+ block_encrypt, block_decrypt,
+ %% deprecated
des_cbc_encrypt, des_cbc_decrypt,
des_cfb_encrypt, des_cfb_decrypt,
des_ecb_encrypt, des_ecb_decrypt,
des3_cbc_encrypt, des3_cbc_decrypt,
des3_cfb_encrypt, des3_cfb_decrypt,
aes_cfb_128_encrypt, aes_cfb_128_decrypt,
+ rc2_cbc_encrypt, rc2_cbc_decrypt,
+ rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
+ aes_cbc_128_encrypt, aes_cbc_128_decrypt,
+ aes_cbc_256_encrypt, aes_cbc_256_decrypt,
+ blowfish_cbc_encrypt, blowfish_cbc_decrypt,
+ blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
+ blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
+ %%
rand_bytes,
strong_rand_bytes,
- strong_rand_mpint,
rand_uniform,
- mod_exp, mod_exp_prime,
+ mod_pow,
+ exor,
+ %% deprecated
+ mod_exp,strong_rand_mpint,erlint, mpint,
+ %%
+ sign, verify, generate_key, compute_key,
+ %% deprecated
dss_verify,dss_sign,
rsa_verify,rsa_sign,
rsa_public_encrypt,rsa_private_decrypt,
rsa_private_encrypt,rsa_public_decrypt,
dh_generate_key, dh_compute_key,
- aes_cbc_128_encrypt, aes_cbc_128_decrypt,
- exor,
+ %%
+ stream_init, stream_encrypt, stream_decrypt,
+ %% deprecated
rc4_encrypt, rc4_set_key, rc4_encrypt_with_state,
- rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
- %% idea_cbc_encrypt, idea_cbc_decrypt,
- aes_cbc_256_encrypt, aes_cbc_256_decrypt,
aes_ctr_encrypt, aes_ctr_decrypt,
aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt,
- aes_cbc_ivec, blowfish_cbc_encrypt, blowfish_cbc_decrypt,
- blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
- blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
- des_cbc_ivec, des_cfb_ivec, erlint, mpint,
- hash, hash_init, hash_update, hash_final,
- hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info,
- rc2_cbc_encrypt, rc2_cbc_decrypt,
- srp_generate_key, srp_compute_key,
- info_lib, algorithms]).
-
+ %%
+ next_iv,
+ %% deprecated
+ aes_cbc_ivec,
+ des_cbc_ivec, des_cfb_ivec,
+ info,
+ %%
+ info_lib, supports]).
+
+-type mpint() :: binary().
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'.
+%%-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'.
-type data_or_digest() :: binary() | {digest, binary()}.
-type crypto_integer() :: binary() | integer().
+%%-type ec_named_curve() :: atom().
+%%-type ec_point() :: crypto_integer().
+%%-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis.
+%%-type ec_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}.
+%%-type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}.
+%%-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}.
+%%-type ec_curve() :: ec_named_curve() | ec_curve_spec().
+%%-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}.
-define(nif_stub,nif_stub_error(?LINE)).
@@ -190,6 +305,22 @@ info_lib() -> ?nif_stub.
algorithms() -> ?nif_stub.
+supports()->
+ Algs = algorithms(),
+ PubKeyAlgs =
+ case lists:member(ec, Algs) of
+ true ->
+ {public_keys, [rsa, dss, ecdsa, dh, srp, ecdh]};
+ false ->
+ {public_keys, [rsa, dss, dh, srp]}
+ end,
+ [{hashs, Algs -- [ec]},
+ {ciphers, [des_cbc, des_cfb, des3_cbc, des3_cbf, des_ede3, blowfish_cbc,
+ blowfish_cfb64, blowfish_ofb64, blowfish_ecb, aes_cbc128, aes_cfb128, aes_cbc256, rc2_cbc, aes_ctr, rc4
+ ]},
+ PubKeyAlgs
+ ].
+
%% Crypto app version history:
%% (no version): Driver implementation
%% 2.0 : NIF implementation, requires OTP R14
@@ -459,7 +590,7 @@ hmac(sha384, Key, Data) -> sha384_mac(Key, Data);
hmac(sha512, Key, Data) -> sha512_mac(Key, Data).
hmac(md5, Key, Data, Size) -> md5_mac_n(Key, Data, Size);
-hmac(sha, Key, Data, Size) -> sha_mac(Key, Data, Size);
+hmac(sha, Key, Data, Size) -> sha_mac_n(Key, Data, Size);
hmac(sha224, Key, Data, Size) -> sha224_mac(Key, Data, Size);
hmac(sha256, Key, Data, Size) -> sha256_mac(Key, Data, Size);
hmac(sha384, Key, Data, Size) -> sha384_mac(Key, Data, Size);
@@ -565,6 +696,114 @@ sha512_mac(Key, Data, MacSz) ->
sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub.
+
+%% Ecrypt/decrypt %%%
+
+-spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_encrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_encrypt(Key, Ivec, Data);
+block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(blowfish_cbc, Key, Ivec, Data) ->
+ blowfish_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_cfb64, Key, Ivec, Data) ->
+ blowfish_cfb64_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_ofb64, Key, Ivec, Data) ->
+ blowfish_ofb64_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_encrypt(Key, Ivec, Data);
+block_encrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_encrypt(Key, Ivec, Data).
+
+-spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_decrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_decrypt(Key, Ivec, Data);
+block_decrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_decrypt(Key, Ivec, Data);
+block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(blowfish_cbc, Key, Ivec, Data) ->
+ blowfish_cbc_decrypt(Key, Ivec, Data);
+block_decrypt(blowfish_cfb64, Key, Ivec, Data) ->
+ blowfish_cfb64_decrypt(Key, Ivec, Data);
+block_decrypt(blowfish_ofb64, Key, Ivec, Data) ->
+ blowfish_ofb64_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_decrypt(Key, Ivec, Data);
+block_decrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_decrypt(Key, Ivec, Data).
+
+-spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_encrypt(des_ecb, Key, Data) ->
+ des_ecb_encrypt(Key, Data);
+block_encrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_encrypt(Key, Data).
+
+-spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_decrypt(des_ecb, Key, Data) ->
+ des_ecb_decrypt(Key, Data);
+block_decrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_decrypt(Key, Data).
+
+-spec next_iv(des_cbc | des3_cbc | aes_cbc, Data::iodata()) -> binary().
+
+next_iv(des_cbc, Data) ->
+ des_cbc_ivec(Data);
+next_iv(des3_cbc, Data) ->
+ des_cbc_ivec(Data);
+next_iv(aes_cbc, Data) ->
+ aes_cbc_ivec(Data).
+
+-spec next_iv(des_cfb, Data::iodata(), Ivec::binary()) -> binary().
+
+next_iv(des_cfb, Data, Ivec) ->
+ des_cfb_ivec(Ivec, Data);
+next_iv(Type, Data, _Ivec) ->
+ next_iv(Type, Data).
+
+stream_init(aes_ctr, Key, Ivec) ->
+ {aes_ctr, aes_ctr_stream_init(Key, Ivec)}.
+stream_init(rc4, Key) ->
+ {rc4, rc4_set_key(Key)}.
+stream_encrypt({aes_ctr, State0}, Data) ->
+ {State, Cipher} = aes_ctr_stream_encrypt(State0, Data),
+ {{aes_ctr, State}, Cipher};
+stream_encrypt({rc4, State0}, Data) ->
+ {State, Cipher} = rc4_encrypt_with_state(State0, Data),
+ {{rc4, State}, Cipher}.
+stream_decrypt({aes_ctr, State0}, Data) ->
+ {State, Text} = aes_ctr_stream_decrypt(State0, Data),
+ {{aes_ctr, State}, Text};
+stream_decrypt({rc4, State0}, Data) ->
+ {State, Text} = rc4_encrypt_with_state (State0, Data),
+ {{rc4, State}, Text}.
+
%%
%% CRYPTO FUNCTIONS
%%
@@ -713,8 +952,12 @@ blowfish_cfb64_decrypt(Key, IVec, Data) ->
bf_cfb64_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+blowfish_ofb64_decrypt(Key, Ivec, Data) ->
+ blowfish_ofb64_encrypt(Key, Ivec, Data).
+
blowfish_ofb64_encrypt(_Key, _IVec, _Data) -> ?nif_stub.
+
%%
%% AES in cipher feedback mode (CFB)
%%
@@ -798,9 +1041,9 @@ mod_exp(Base, Exponent, Modulo)
mod_exp(Base, Exponent, Modulo) ->
mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4).
--spec mod_exp_prime(binary(), binary(), binary()) -> binary() | error.
-mod_exp_prime(Base, Exponent, Prime) ->
- case mod_exp_nif(Base, Exponent, Prime, 0) of
+-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error.
+mod_pow(Base, Exponent, Prime) ->
+ case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
<<0>> -> error;
R -> R
end.
@@ -819,19 +1062,40 @@ mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub.
%% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey
dss_verify(Data,Signature,Key) ->
- dss_verify(sha, Data, Signature, Key).
-dss_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub.
+ dss_verify(sha, Data, Signature, Key).
+
+dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none ->
+ verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key));
+dss_verify(Type,Digest,Signature,Key) ->
+ verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)).
% Key = [E,N] E=PublicExponent N=PublicModulus
rsa_verify(Data,Signature,Key) ->
- rsa_verify_nif(sha, Data,Signature,Key).
-rsa_verify(Type, DataOrDigest, Signature, Key) ->
- case rsa_verify_nif(Type, DataOrDigest, Signature, Key) of
+ rsa_verify(sha, Data,Signature,Key).
+rsa_verify(Type, Data, Signature, Key) when is_binary(Data) ->
+ verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key));
+rsa_verify(Type, Digest, Signature, Key) ->
+ verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)).
+
+
+verify(dss, Type, Data, Signature, Key) ->
+ dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key));
+
+verify(rsa, Type, DataOrDigest, Signature, Key) ->
+ case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of
notsup -> erlang:error(notsup);
Bool -> Bool
+ end;
+verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) ->
+ case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key(Curve, undefined, Key)) of
+ notsup -> erlang:error(notsup);
+ Bool -> Bool
end.
+
+dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
+ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub.
%%
@@ -845,24 +1109,103 @@ rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
dss_sign(DataOrDigest,Key) ->
dss_sign(sha,DataOrDigest,Key).
-dss_sign(Type, DataOrDigest, Key) ->
- case dss_sign_nif(Type,DataOrDigest,Key) of
- error -> erlang:error(badkey, [DataOrDigest, Key]);
- Sign -> Sign
- end.
+dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none ->
+ sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+dss_sign(Type, Digest, Key) ->
+ sign(dss, Type, Digest, map_mpint_to_bin(Key)).
-dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent
rsa_sign(DataOrDigest,Key) ->
rsa_sign(sha, DataOrDigest, Key).
-rsa_sign(Type, DataOrDigest, Key) ->
- case rsa_sign_nif(Type,DataOrDigest,Key) of
+
+rsa_sign(Type, Data, Key) when is_binary(Data) ->
+ sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+rsa_sign(Type, Digest, Key) ->
+ sign(rsa, Type, Digest, map_mpint_to_bin(Key)).
+
+map_mpint_to_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List ).
+
+map_ensure_int_as_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_ensure_int_as_bin(List) ->
+ List.
+
+ensure_int_as_bin(Int) when is_integer(Int) ->
+ int_to_bin(Int);
+ensure_int_as_bin(Bin) ->
+ Bin.
+
+map_to_norm_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_to_norm_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List).
+
+
+sign(rsa, Type, DataOrDigest, Key) ->
+ case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
+ Sign -> Sign
+ end;
+sign(dss, Type, DataOrDigest, Key) ->
+ case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [DataOrDigest, Key]);
+ Sign -> Sign
+ end;
+sign(ecdsa, Type, DataOrDigest, [Key, Curve]) ->
+ case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key(Curve, Key, undefined)) of
error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
Sign -> Sign
end.
rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub.
+
+
+
+
+-spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) ->
+ binary().
+-spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+
+public_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N,D]
+private_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+
+%% Binary, Key = [E,N,D]
+private_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N]
+public_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
%%
@@ -872,16 +1215,16 @@ rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
-spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) ->
binary().
--spec rsa_public_decrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
--spec rsa_private_encrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
--spec rsa_private_decrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
%% Binary, Key = [E,N]
rsa_public_encrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, Key, Padding, true) of
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
error ->
erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -891,7 +1234,7 @@ rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
%% Binary, Key = [E,N,D]
rsa_private_decrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, Key, Padding, false) of
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
error ->
erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -902,7 +1245,7 @@ rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
%% Binary, Key = [E,N,D]
rsa_private_encrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, Key, Padding, true) of
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
error ->
erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -910,7 +1253,7 @@ rsa_private_encrypt(BinMesg, Key, Padding) ->
%% Binary, Key = [E,N]
rsa_public_decrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, Key, Padding, false) of
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
error ->
erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -1052,120 +1395,135 @@ dh_check([_Prime,_Gen]) -> ?nif_stub.
{binary(),binary()}.
dh_generate_key(DHParameters) ->
- dh_generate_key(undefined, DHParameters).
+ dh_generate_key_nif(undefined, map_mpint_to_bin(DHParameters), 4).
dh_generate_key(PrivateKey, DHParameters) ->
- case dh_generate_key_nif(PrivateKey, DHParameters) of
- error -> erlang:error(generation_failed, [PrivateKey,DHParameters]);
- Res -> Res
- end.
+ dh_generate_key_nif(mpint_to_bin(PrivateKey), map_mpint_to_bin(DHParameters), 4).
-dh_generate_key_nif(_PrivateKey, _DHParameters) -> ?nif_stub.
+dh_generate_key_nif(_PrivateKey, _DHParameters, _Mpint) -> ?nif_stub.
%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
-%% MyPrivKey, OthersPublicKey = mpint()
+%% MyPrivKey, OthersPublicKey = mpint()
-spec dh_compute_key(binary(), binary(), [binary()]) -> binary().
dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
- case dh_compute_key_nif(OthersPublicKey,MyPrivateKey,DHParameters) of
- error -> erlang:error(computation_failed, [OthersPublicKey,MyPrivateKey,DHParameters]);
- Ret -> Ret
- end.
+ compute_key(dh, mpint_to_bin(OthersPublicKey), mpint_to_bin(MyPrivateKey),
+ map_mpint_to_bin(DHParameters)).
+
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
+generate_key(Type, Params) ->
+ generate_key(Type, Params, undefined).
+
+generate_key(dh, DHParameters, PrivateKey) ->
+ dh_generate_key_nif(ensure_int_as_bin(PrivateKey),
+ map_ensure_int_as_bin(DHParameters), 0);
+
+generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg)
+ when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) ->
+ Private = case PrivArg of
+ undefined -> random_bytes(32);
+ _ -> ensure_int_as_bin(PrivArg)
+ end,
+ host_srp_gen_key(Private, Verifier, Generator, Prime, Version);
-%%% SRP
--spec srp_generate_key(binary(), binary(), atom() | binary(), atom() | binary() ) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Verifier, Generator, Prime, Version) when is_binary(Verifier),
- is_binary(Generator),
- is_binary(Prime),
- is_atom(Version) ->
- Private = random_bytes(32),
- server_srp_gen_key(Private, Verifier, Generator, Prime, Version);
-
-srp_generate_key(Generator, Prime, Version, Private) when is_binary(Generator),
- is_binary(Prime),
- is_atom(Version),
- is_binary(Private) ->
- client_srp_gen_key(Private, Generator, Prime).
-
--spec srp_generate_key(binary(), binary(), binary(), atom(), binary()) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Verifier, Generator, Prime, Version, Private) when is_binary(Verifier),
- is_binary(Generator),
- is_binary(Prime),
- is_atom(Version),
- is_binary(Private)
- ->
- server_srp_gen_key(Private, Verifier, Generator, Prime, Version).
-
--spec srp_generate_key(binary(), binary(), atom()) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Generator, Prime, Version) when is_binary(Generator),
- is_binary(Prime),
- is_atom(Version) ->
- Private = random_bytes(32),
- client_srp_gen_key(Private, Generator, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()| binary(), atom() | binary() ) -> binary().
-srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate, ServerPublic, Version) when
- is_binary(Prime),
+generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
+ when is_binary(Generator), is_binary(Prime), is_atom(Version) ->
+ Private = case PrivateArg of
+ undefined -> random_bytes(32);
+ _ -> PrivateArg
+ end,
+ user_srp_gen_key(Private, Generator, Prime);
+
+generate_key(ecdh, Curve, undefined) ->
+ ec_key_to_term_nif(ec_key_generate(Curve)).
+
+
+ec_key_generate(_Key) -> ?nif_stub.
+
+
+compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
+ case dh_compute_key_nif(ensure_int_as_bin(OthersPublicKey),
+ ensure_int_as_bin(MyPrivateKey),
+ map_ensure_int_as_bin(DHParameters)) of
+ error -> erlang:error(computation_failed,
+ [OthersPublicKey,MyPrivateKey,DHParameters]);
+ Ret -> Ret
+ end;
+
+compute_key(srp, HostPublic, {UserPublic, UserPrivate},
+ {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when
+ is_binary(Prime),
is_binary(Generator),
- is_binary(ClientPublic),
- is_binary(ClientPrivate),
- is_binary(ServerPublic),
is_atom(Version) ->
+ HostPubBin = ensure_int_as_bin(HostPublic),
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
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, ensure_int_as_bin(UserPublic),
+ HostPubBin, Prime);
+ [S] -> S
+ end,
+ srp_user_secret_nif(ensure_int_as_bin(UserPrivate), Scrambler, HostPubBin,
+ Multiplier, Generator, DerivedKey, Prime);
+
+compute_key(srp, UserPublic, {HostPublic, HostPrivate},
+ {host,[Verifier, Prime, Version | ScramblerArg]}) when
is_binary(Verifier),
- is_binary(Prime),
- is_binary(ClientPublic),
- is_binary(ServerPublic),
- is_binary(ServerPrivate),
+ is_binary(Prime),
is_atom(Version) ->
- Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
- srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
+ UserPubBin = ensure_int_as_bin(UserPublic),
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, UserPubBin, ensure_int_as_bin(HostPublic), Prime);
+ [S] -> S
+ end,
+ srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler,
+ UserPubBin, Prime);
+
+compute_key(ecdh, Others, My, Curve) ->
+ ecdh_compute_key_nif(ensure_int_as_bin(Others),
+ term_to_ec_key(Curve,My,undefined)).
+
+ecdh_compute_key_nif(_Others, _My) -> ?nif_stub.
+
%%
+%% EC
+%%
+ec_key_to_term_nif(_Key) -> ?nif_stub.
+
+term_to_nif_prime({prime_field, Prime}) ->
+ {prime_field, int_to_bin(Prime)};
+term_to_nif_prime(PrimeField) ->
+ PrimeField.
+term_to_nif_curve({A, B, Seed}) ->
+ {ensure_int_as_bin(A), ensure_int_as_bin(B), Seed}.
+term_to_nif_curve_parameters({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
+ {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), int_to_bin(Order), int_to_bin(CoFactor)};
+term_to_nif_curve_parameters(Curve) when is_atom(Curve) ->
+ %% named curve
+ Curve.
+
+term_to_ec_key(Curve, PrivKey, PubKey) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve),
+ ensure_int_as_bin(PrivKey),
+ ensure_int_as_bin(PubKey)).
+
+term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub.
+
+
+
%% LOCAL FUNCTIONS
%%
-client_srp_gen_key(Private, Generator, Prime) ->
- case mod_exp_prime(Generator, Private, Prime) of
+user_srp_gen_key(Private, Generator, Prime) ->
+ case mod_pow(Generator, Private, Prime) of
error ->
error;
Public ->
{Public, Private}
end.
-server_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
+host_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
Multiplier = srp_multiplier(Version, Generator, Prime),
case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of
error ->
@@ -1185,17 +1543,17 @@ srp_multiplier('6', _, _) ->
srp_multiplier('3', _, _) ->
<<1/integer>>.
-srp_scrambler(Version, ClientPublic, ServerPublic, Prime) when Version == '6'; Version == '6a'->
+srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'->
%% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html
PadLength = erlang:byte_size(Prime),
C0 = sha_init(),
- C1 = sha_update(C0, srp_pad_to(PadLength, ClientPublic)),
- C2 = sha_update(C1, srp_pad_to(PadLength, ServerPublic)),
+ C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)),
+ C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)),
sha_final(C2);
-srp_scrambler('3', _, ServerPublic, _Prime) ->
+srp_scrambler('3', _, HostPublic, _Prime) ->
%% The parameter u is a 32-bit unsigned integer which takes its value
%% from the first 32 bits of the SHA1 hash of B, MSB first.
- <<U:32/bits, _/binary>> = sha(ServerPublic),
+ <<U:32/bits, _/binary>> = sha(HostPublic),
U.
srp_pad_length(Width, Length) ->
@@ -1207,9 +1565,9 @@ srp_pad_to(Width, Binary) ->
N -> << 0:(N*8), Binary/binary>>
end.
-srp_server_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
-srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
@@ -1252,11 +1610,15 @@ int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
int_to_bin_neg(X,Ds) ->
int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
+bytes_to_integer(Bin) ->
+ bin_to_int(Bin).
-bin_to_int(Bin) ->
+bin_to_int(Bin) when is_binary(Bin) ->
Bits = bit_size(Bin),
<<Integer:Bits/integer>> = Bin,
- Integer.
+ Integer;
+bin_to_int(undefined) ->
+ undefined.
%% int from integer in a binary with 32bit length
erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile
index ec8136b455..07e5c1b754 100644
--- a/lib/crypto/test/Makefile
+++ b/lib/crypto/test/Makefile
@@ -7,7 +7,8 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES = \
blowfish_SUITE \
- crypto_SUITE
+ crypto_SUITE \
+ old_crypto_SUITE
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 08ecad3233..c007ecac86 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -18,105 +18,104 @@
%%
-module(crypto_SUITE).
--include_lib("test_server/include/test_server.hrl").
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
- info/1,
- link_test/1,
- md5/1,
- md5_update/1,
- md4/1,
- md4_update/1,
- sha/1,
- sha_update/1,
- hmac_update_sha/1,
- hmac_update_sha_n/1,
- hmac_update_sha256/1,
- hmac_update_sha512/1,
- hmac_update_md5/1,
- hmac_update_md5_io/1,
- hmac_update_md5_n/1,
- hmac_rfc2202/1,
- hmac_rfc4231_sha224/1,
- hmac_rfc4231_sha256/1,
- hmac_rfc4231_sha384/1,
- hmac_rfc4231_sha512/1,
- ripemd160/1,
- ripemd160_update/1,
- sha256/1,
- sha256_update/1,
- sha512/1,
- sha512_update/1,
- md5_mac/1,
- md5_mac_io/1,
- des_cbc/1,
- des_cbc_iter/1,
- des_cfb/1,
- des_cfb_iter/1,
- des_ecb/1,
- des3_cbc/1,
- des3_cfb/1,
- rc2_cbc/1,
- aes_cfb/1,
- aes_cbc/1,
- aes_cbc_iter/1,
- aes_ctr/1,
- aes_ctr_stream/1,
- mod_exp_test/1,
- rand_uniform_test/1,
- strong_rand_test/1,
- rsa_verify_test/1,
- dsa_verify_test/1,
- rsa_sign_test/1,
- rsa_sign_hash_test/1,
- dsa_sign_test/1,
- 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,
- blowfish_cfb64/1,
- smp/1]).
-
--export([hexstr2bin/1]).
+-include_lib("common_test/include/ct.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [link_test, {group, info}].
-
-groups() ->
- [{info, [sequence],[info, {group, rest}]},
- {rest, [],
- [md5, md5_update, md4, md4_update, md5_mac,
- md5_mac_io, ripemd160, ripemd160_update, sha, sha_update,
- 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_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, srp3, srp6, srp6a, exor_test,
- rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
- smp]}].
-
+ [app,
+ {group, md4},
+ {group, md5},
+ {group, ripemd160},
+ {group, sha},
+ {group, sha224},
+ {group, sha256},
+ {group, sha384},
+ {group, sha512},
+ {group, rsa},
+ {group, dss},
+ {group, ecdsa},
+ {group, dh},
+ {group, ecdh},
+ {group, srp},
+ {group, des_cbc},
+ {group, des_cfb},
+ {group, des3_cbc},
+ {group, des3_cbf},
+ %%{group, des_ede3},
+ {group, blowfish_cbc},
+ {group, blowfish_ecb},
+ {group, blowfish_cfb64},
+ {group, blowfish_ofb64},
+ {group, aes_cbc128},
+ {group, aes_cfb128},
+ {group, aes_cbc256},
+ {group, rc2_cbc},
+ {group, rc4},
+ {group, aes_ctr},
+ mod_pow,
+ exor
+ ].
+
+groups() ->
+ [{md4, [], [hash]},
+ {md5, [], [hash, hmac]},
+ {ripemd160, [], [hash]},
+ {sha, [], [hash, hmac]},
+ {sha224, [], [hash, hmac]},
+ {sha256, [], [hash, hmac]},
+ {sha384, [], [hash, hmac]},
+ {sha512, [], [hash, hmac]},
+ {rsa, [], [sign_verify,
+ public_encrypt
+ ]},
+ {dss, [], [sign_verify]},
+ {ecdsa, [], [sign_verify]},
+ {dh, [], [generate_compute]},
+ {ecdh, [], [compute]},
+ {srp, [], [generate_compute]},
+ {des_cbc, [], [block]},
+ {des_cfb, [], [block]},
+ {des3_cbc,[], [block]},
+ {des3_cbf,[], [block]},
+ {rc2_cbc,[], [block]},
+ {aes_cbc128,[], [block]},
+ {aes_cfb128,[], [block]},
+ {aes_cbc256,[], [block]},
+ {blowfish_cbc, [], [block]},
+ {blowfish_ecb, [], [block]},
+ {blowfish_cfb64, [], [block]},
+ {blowfish_ofb64,[], [block]},
+ {rc4, [], [stream]},
+ {aes_ctr, [], [stream]}
+ ].
+
+%%-------------------------------------------------------------------
init_per_suite(Config) ->
- Config.
+ try crypto:start() of
+ ok ->
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
end_per_suite(_Config) ->
- ok.
+ application:stop(crypto).
-init_per_group(_GroupName, Config) ->
- Config.
+%%-------------------------------------------------------------------
+init_per_group(GroupName, Config) ->
+ case is_supported(GroupName) of
+ true ->
+ group_config(GroupName, Config);
+ false ->
+ {skip, "Group not supported"}
+ end.
end_per_group(_GroupName, Config) ->
Config.
@@ -124,1733 +123,1098 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(info, Config) ->
Config;
init_per_testcase(_Name,Config) ->
- io:format("init_per_testcase\n"),
- ?line crypto:start(),
Config.
end_per_testcase(info, Config) ->
Config;
end_per_testcase(_Name,Config) ->
- io:format("end_per_testcase\n"),
- ?line crypto:stop(),
Config.
-%%
-%%
-link_test(doc) ->
- ["Test that the library is statically linked to libcrypto.a."];
-link_test(suite) ->
- [];
-link_test(Config) when is_list(Config) ->
- ?line case os:type() of
- {unix,darwin} -> {skipped,"Darwin cannot link statically"};
- {unix,_} -> link_test_1();
- _ -> {skip,"Only runs on Unix"}
- end.
-
-link_test_1() ->
- ?line CryptoPriv = code:priv_dir(crypto),
- ?line Wc = filename:join([CryptoPriv,"lib","crypto.*"]),
- ?line case filelib:wildcard(Wc) of
- [] -> {skip,"Didn't find the crypto driver"};
- [Drv] -> link_test_2(Drv)
- end.
-
-link_test_2(Drv) ->
- case ldd_program() of
- none ->
- {skip,"No ldd-like program found"};
- Ldd ->
- Cmd = Ldd ++ " " ++ Drv,
- Libs = os:cmd(Cmd),
- io:format("~p\n", [Libs]),
- case string:str(Libs, "libcrypto") of
- 0 ->
- case ?t:is_commercial() of
- true ->
- ?t:fail({libcrypto,statically_linked});
- false ->
- {comment,"Statically linked (OK for open-source platform)"}
- end;
- _ ->
- ok
- end
- end.
-
-ldd_program() ->
- case os:find_executable("ldd") of
- false ->
- case os:type() of
- {unix,darwin} ->
- case os:find_executable("otool") of
- false -> none;
- Otool -> Otool ++ " -L"
- end
- end;
- Ldd when is_list(Ldd) -> Ldd
- end.
-
-%%
-%%
-info(doc) ->
- ["Call the info function."];
-info(suite) ->
- [];
-info(Config) when is_list(Config) ->
- case {code:lib_dir(crypto),?t:is_commercial()} of
- {{error,bad_name},false} ->
- {skip,"Missing crypto application"};
- {_,_} ->
- ?line crypto:start(),
- ?line Info = crypto:info(),
- ?line Exports = lists:usort([F || {F,_} <- crypto:module_info(exports)]),
- ?line [] = Info -- Exports,
- ?line NotInInfo = Exports -- Info,
- io:format("NotInInfo = ~p\n", [NotInInfo]),
- BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
- dh_check, dh_generate_parameters,
- module_info, start, stop, version]),
- ?line BlackList = NotInInfo,
-
- ?line InfoLib = crypto:info_lib(),
- ?line [_|_] = InfoLib,
- F = fun([{Name,VerN,VerS}|T],Me) ->
- ?line true = is_binary(Name),
- ?line true = is_integer(VerN),
- ?line true = is_binary(VerS),
- Me(T,Me);
- ([],_) ->
- ok
- end,
- ?line F(InfoLib,F),
- ?line crypto:stop()
- end.
-
-%%
-%%
-md5(doc) ->
- ["Generate MD5 message digests and check the result. Examples are "
- "from RFC-1321."];
-md5(suite) ->
- [];
-md5(Config) when is_list(Config) ->
- ?line m(crypto:md5(""),
- hexstr2bin("d41d8cd98f00b204e9800998ecf8427e")),
- ?line m(crypto:md5("a"),
- hexstr2bin("0cc175b9c0f1b6a831c399e269772661")),
- ?line m(crypto:md5("abc"),
- hexstr2bin("900150983cd24fb0d6963f7d28e17f72")),
- ?line m(crypto:md5("message digest"),
- hexstr2bin("f96b697d7cb7938d525a2f31aaf161d0")),
- ?line m(crypto:md5("abcdefghijklmnopqrstuvwxyz"),
- hexstr2bin("c3fcd3d76192e4007dfb496cca67e13b")),
- ?line m(crypto:md5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"),
- hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")),
- ?line m(crypto:md5("12345678901234567890123456789012345678901234567890"
- "123456789012345678901234567890"),
- hexstr2bin("57edf4a22be3c955ac49da2e2107b67a")).
-
-%%
-%%
-md5_update(doc) ->
- ["Generate MD5 message using md5_init, md5_update, and md5_final, and"
- "check the result. Examples are from RFC-1321."];
-md5_update(suite) ->
- [];
-md5_update(Config) when is_list(Config) ->
- ?line Ctx = crypto:md5_init(),
- ?line Ctx1 = crypto:md5_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
- ?line Ctx2 = crypto:md5_update(Ctx1, "abcdefghijklmnopqrstuvwxyz"
- "0123456789"),
- ?line m(crypto:md5_final(Ctx2),
- hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")).
-
-%%
-%%
-md4(doc) ->
- ["Generate MD4 message digests and check the result. Examples are "
- "from RFC-1321."];
-md4(suite) ->
- [];
-md4(Config) when is_list(Config) ->
- ?line m(crypto:md4(""),
- hexstr2bin("31d6cfe0d16ae931b73c59d7e0c089c0")),
- ?line m(crypto:md4("a"),
- hexstr2bin("bde52cb31de33e46245e05fbdbd6fb24")),
- ?line m(crypto:md4("abc"),
- hexstr2bin("a448017aaf21d8525fc10ae87aa6729d")),
- ?line m(crypto:md4("message digest"),
- hexstr2bin("d9130a8164549fe818874806e1c7014b")),
- ?line m(crypto:md4("abcdefghijklmnopqrstuvwxyz"),
- hexstr2bin("d79e1c308aa5bbcdeea8ed63df412da9")),
- ?line m(crypto:md4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"),
- hexstr2bin("043f8582f241db351ce627e153e7f0e4")),
- ?line m(crypto:md4("12345678901234567890123456789012345678901234567890"
- "123456789012345678901234567890"),
- hexstr2bin("e33b4ddc9c38f2199c3e7b164fcc0536")).
-
-%%
-%%
-md4_update(doc) ->
- ["Generate MD5 message using md5_init, md5_update, and md5_final, and"
- "check the result. Examples are from RFC-1321."];
-md4_update(suite) ->
- [];
-md4_update(Config) when is_list(Config) ->
- ?line Ctx = crypto:md4_init(),
- ?line Ctx1 = crypto:md4_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
- ?line Ctx2 = crypto:md4_update(Ctx1, "abcdefghijklmnopqrstuvwxyz"
- "0123456789"),
- ?line m(crypto:md4_final(Ctx2),
- hexstr2bin("043f8582f241db351ce627e153e7f0e4")).
-
-%%
-%%
-sha(doc) ->
- ["Generate SHA message digests and check the result. Examples are "
- "from FIPS-180-1."];
-sha(suite) ->
- [];
-sha(Config) when is_list(Config) ->
- ?line m(crypto:sha("abc"),
- hexstr2bin("A9993E364706816ABA3E25717850C26C9CD0D89D")),
- ?line m(crypto:sha("abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
- "nlmnomnopnopq"),
- hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")).
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+app() ->
+ [{doc, "Test that the crypto app file is ok"}].
+app(Config) when is_list(Config) ->
+ ok = ?t:app_test(crypto).
+%%--------------------------------------------------------------------
+hash() ->
+ [{doc, "Test all different hash functions"}].
+hash(Config) when is_list(Config) ->
+ {Type, Msgs, Digests} = proplists:get_value(hash, Config),
+ [LongMsg | _] = lists:reverse(Msgs),
+ Inc = iolistify(LongMsg),
+ [IncrDigest | _] = lists:reverse(Digests),
+ hash(Type, Msgs, Digests),
+ hash(Type, lists:map(fun iolistify/1, Msgs), Digests),
+ hash_increment(Type, Inc, IncrDigest).
+%%--------------------------------------------------------------------
+hmac() ->
+ [{doc, "Test all different hmac functions"}].
+hmac(Config) when is_list(Config) ->
+ {Type, Keys, Data, Expected} = proplists:get_value(hmac, Config),
+ hmac(Type, Keys, Data, Expected),
+ hmac(Type, lists:map(fun iolistify/1, Keys), lists:map(fun iolistify/1, Data), Expected),
+ hmac_increment(Type).
+%%--------------------------------------------------------------------
+block() ->
+ [{doc, "Test block ciphers"}].
+block(Config) when is_list(Config) ->
+ Blocks = proplists:get_value(block, Config),
+ lists:foreach(fun block_cipher/1, Blocks),
+ lists:foreach(fun block_cipher/1, block_iolistify(Blocks)),
+ lists:foreach(fun block_cipher_increment/1, block_iolistify(Blocks)).
+
+%%--------------------------------------------------------------------
+stream() ->
+ [{doc, "Test stream ciphers"}].
+stream(Config) when is_list(Config) ->
+ Streams = proplists:get_value(stream, Config),
+ lists:foreach(fun stream_cipher/1, Streams),
+ lists:foreach(fun stream_cipher/1, stream_iolistify(Streams)),
+ lists:foreach(fun stream_cipher_incment/1, stream_iolistify(Streams)).
+
+%%--------------------------------------------------------------------
+sign_verify() ->
+ [{doc, "Sign/verify digital signatures"}].
+sign_verify(Config) when is_list(Config) ->
+ SignVerify = proplists:get_value(sign_verify, Config),
+ lists:foreach(fun do_sign_verify/1, SignVerify).
+
+%%--------------------------------------------------------------------
+public_encrypt() ->
+ [{doc, "Test public_encrypt/decrypt and private_encrypt/decrypt functions. "}].
+public_encrypt(Config) when is_list(Config) ->
+ Params = proplists:get_value(pub_priv_encrypt, Config),
+ lists:foreach(fun do_public_encrypt/1, Params),
+ lists:foreach(fun do_private_encrypt/1, Params).
+
+%%--------------------------------------------------------------------
+generate_compute() ->
+ [{doc, " Test crypto:genarate_key and crypto:compute_key"}].
+generate_compute(Config) when is_list(Config) ->
+ GenCom = proplists:get_value(generate_compute, Config),
+ lists:foreach(fun do_generate_compute/1, GenCom).
+%%--------------------------------------------------------------------
+compute() ->
+ [{doc, " Test crypto:compute_key"}].
+compute(Config) when is_list(Config) ->
+ Gen = proplists:get_value(compute, Config),
+ lists:foreach(fun do_compute/1, Gen).
+%%--------------------------------------------------------------------
+mod_pow() ->
+ [{doc, "mod_pow testing (A ^ M % P with bignums)"}].
+mod_pow(Config) when is_list(Config) ->
+ mod_pow_aux_test(2, 5, 10, 8).
+%%--------------------------------------------------------------------
+exor() ->
+ [{doc, "Test the exor function"}].
+exor(Config) when is_list(Config) ->
+ B = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>,
+ Z1 = zero_bin(B),
+ Z1 = crypto:exor(B, B),
+ B1 = crypto:rand_bytes(100),
+ B2 = crypto:rand_bytes(100),
+ Z2 = zero_bin(B1),
+ Z2 = crypto:exor(B1, B1),
+ Z2 = crypto:exor(B2, B2),
+ R = xor_bytes(B1, B2),
+ R = crypto:exor(B1, B2).
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
-%%
-hmac_update_sha_n(doc) ->
- ["Request a larger-than-allowed SHA1 HMAC using hmac_init, hmac_update, and hmac_final_n. "
- "Expected values for examples are generated using crypto:sha_mac." ];
-hmac_update_sha_n(suite) ->
- [];
-hmac_update_sha_n(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("00010203101112132021222330313233"
- "04050607141516172425262734353637"
- "08090a0b18191a1b28292a2b38393a3b"
- "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(sha, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final_n(Ctx3, 1024),
- ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac),
- ?line m(size(Exp), size(Mac)).
-
-
-hmac_update_sha(doc) ->
- ["Generate an SHA1 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:sha_mac." ];
-hmac_update_sha(suite) ->
- [];
-hmac_update_sha(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("00010203101112132021222330313233"
- "04050607141516172425262734353637"
- "08090a0b18191a1b28292a2b38393a3b"
- "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(sha, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-
-hmac_update_sha256(doc) ->
- ["Generate an SHA256 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:sha256_mac." ];
-hmac_update_sha256(suite) ->
- [];
-hmac_update_sha256(Config) when is_list(Config) ->
- if_supported(sha256, fun() -> hmac_update_sha256_do() end).
-
-hmac_update_sha256_do() ->
- ?line Key = hexstr2bin("00010203101112132021222330313233"
- "04050607141516172425262734353637"
- "08090a0b18191a1b28292a2b38393a3b"
- "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(sha256, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-
-hmac_update_sha512(doc) ->
- ["Generate an SHA512 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:sha512_mac." ];
-hmac_update_sha512(suite) ->
- [];
-hmac_update_sha512(Config) when is_list(Config) ->
- if_supported(sha512, fun() -> hmac_update_sha512_do() end).
-
-hmac_update_sha512_do() ->
- ?line Key = hexstr2bin("00010203101112132021222330313233"
- "04050607141516172425262734353637"
- "08090a0b18191a1b28292a2b38393a3b"
- "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(sha512, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha512_mac(Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-
-hmac_update_md5(doc) ->
- ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:md5_mac." ];
-hmac_update_md5(suite) ->
- [];
-hmac_update_md5(Config) when is_list(Config) ->
- % ?line Key2 = ["A fine speach", "by a fine man!"],
- Key2 = "A fine speach by a fine man!",
- ?line Long1 = "Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.",
- ?line Long2 = "Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.",
- ?line Long3 = "But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us-that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion that we here highly resolve that these dead shall not have died in vain-that this nation, under God, shall have a new birth of freedom-and that government of the people, by the people, for the people, shall not perish from the earth.",
- ?line CtxA = crypto:hmac_init(md5, Key2),
- ?line CtxB = crypto:hmac_update(CtxA, Long1),
- ?line CtxC = crypto:hmac_update(CtxB, Long2),
- ?line CtxD = crypto:hmac_update(CtxC, Long3),
- ?line Mac2 = crypto:hmac_final(CtxD),
- ?line Exp2 = crypto:md5_mac(Key2, lists:flatten([Long1, Long2, Long3])),
- ?line m(Exp2, Mac2).
-
-hmac_rfc2202(doc) ->
- ["Generate an HMAC using hmac, md5_mac, and sha_mac."
- "Test vectors are taken from RFC-2202."];
-hmac_rfc2202(suite) ->
- [];
-hmac_rfc2202(Config) when is_list(Config) ->
- hmac_rfc2202_md5(),
- hmac_rfc2202_sha().
-
-hmac_rfc2202_md5() ->
- %% Test case 1
- Case1Key = binary:copy(<<16#0b>>, 16),
- Case1Data = <<"Hi There">>,
- Case1Exp = hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d"),
-
- ?line Case1Mac_1 = crypto:md5_mac(Case1Key, Case1Data),
- ?line Case1Mac_2 = crypto:hmac(md5, Case1Key, Case1Data),
- ?line m(Case1Exp, Case1Mac_1),
- ?line m(Case1Exp, Case1Mac_2),
-
- %% Test case 2
- Case2Key = <<"Jefe">>,
- Case2Data = <<"what do ya want for nothing?">>,
- Case2Exp = hexstr2bin("750c783e6ab0b503eaa86e310a5db738"),
-
- ?line Case2Mac_1 = crypto:md5_mac(Case2Key, Case2Data),
- ?line Case2Mac_2 = crypto:hmac(md5, Case2Key, Case2Data),
- ?line m(Case2Exp, Case2Mac_1),
- ?line m(Case2Exp, Case2Mac_2),
-
- %% Test case 3
- Case3Key = binary:copy(<<16#aa>>, 16),
- Case3Data = binary:copy(<<16#dd>>, 50),
- Case3Exp = hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6"),
-
- ?line Case3Mac_1 = crypto:md5_mac(Case3Key, Case3Data),
- ?line Case3Mac_2 = crypto:hmac(md5, Case3Key, Case3Data),
- ?line m(Case3Exp, Case3Mac_1),
- ?line m(Case3Exp, Case3Mac_2),
-
- %% Test case 4
- Case4Key = list_to_binary(lists:seq(1, 16#19)),
- Case4Data = binary:copy(<<16#cd>>, 50),
- Case4Exp = hexstr2bin("697eaf0aca3a3aea3a75164746ffaa79"),
-
- ?line Case4Mac_1 = crypto:md5_mac(Case4Key, Case4Data),
- ?line Case4Mac_2 = crypto:hmac(md5, Case4Key, Case4Data),
- ?line m(Case4Exp, Case4Mac_1),
- ?line m(Case4Exp, Case4Mac_2),
-
- %% Test case 5
- Case5Key = binary:copy(<<16#0c>>, 16),
- Case5Data = "Test With Truncation",
- Case5Exp = hexstr2bin("56461ef2342edc00f9bab995690efd4c"),
- Case5Exp96 = hexstr2bin("56461ef2342edc00f9bab995"),
-
- ?line Case5Mac_1 = crypto:md5_mac(Case5Key, Case5Data),
- ?line Case5Mac_2 = crypto:hmac(md5, Case5Key, Case5Data),
- ?line Case5Mac96_1 = crypto:md5_mac_96(Case5Key, Case5Data),
- ?line Case5Mac96_2 = crypto:hmac(md5, Case5Key, Case5Data, 12),
- ?line m(Case5Exp, Case5Mac_1),
- ?line m(Case5Exp, Case5Mac_2),
- ?line m(Case5Exp96, Case5Mac96_1),
- ?line m(Case5Exp96, Case5Mac96_2),
-
- %% Test case 6
- Case6Key = binary:copy(<<16#aa>>, 80),
- Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- Case6Exp = hexstr2bin("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"),
-
- ?line Case6Mac_1 = crypto:md5_mac(Case6Key, Case6Data),
- ?line Case6Mac_2 = crypto:hmac(md5, Case6Key, Case6Data),
- ?line m(Case6Exp, Case6Mac_1),
- ?line m(Case6Exp, Case6Mac_2),
-
- %% Test case 7
- Case7Key = binary:copy(<<16#aa>>, 80),
- Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
- Case7Exp = hexstr2bin("6f630fad67cda0ee1fb1f562db3aa53e"),
-
- ?line Case7Mac_1 = crypto:md5_mac(Case7Key, Case7Data),
- ?line Case7Mac_2 = crypto:hmac(md5, Case7Key, Case7Data),
- ?line m(Case7Exp, Case7Mac_1),
- ?line m(Case7Exp, Case7Mac_2).
-
-hmac_rfc2202_sha() ->
- %% Test case 1
- Case1Key = binary:copy(<<16#0b>>, 20),
- Case1Data = <<"Hi There">>,
- Case1Exp = hexstr2bin("b617318655057264e28bc0b6fb378c8ef146be00"),
-
- ?line Case1Mac_1 = crypto:sha_mac(Case1Key, Case1Data),
- ?line Case1Mac_2 = crypto:hmac(sha, Case1Key, Case1Data),
- ?line m(Case1Exp, Case1Mac_1),
- ?line m(Case1Exp, Case1Mac_2),
-
- %% Test case 2
- Case2Key = <<"Jefe">>,
- Case2Data = <<"what do ya want for nothing?">>,
- Case2Exp = hexstr2bin("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"),
-
- ?line Case2Mac_1 = crypto:sha_mac(Case2Key, Case2Data),
- ?line Case2Mac_2 = crypto:hmac(sha, Case2Key, Case2Data),
- ?line m(Case2Exp, Case2Mac_1),
- ?line m(Case2Exp, Case2Mac_2),
-
- %% Test case 3
- Case3Key = binary:copy(<<16#aa>>, 20),
- Case3Data = binary:copy(<<16#dd>>, 50),
- Case3Exp = hexstr2bin("125d7342b9ac11cd91a39af48aa17b4f63f175d3"),
-
- ?line Case3Mac_1 = crypto:sha_mac(Case3Key, Case3Data),
- ?line Case3Mac_2 = crypto:hmac(sha, Case3Key, Case3Data),
- ?line m(Case3Exp, Case3Mac_1),
- ?line m(Case3Exp, Case3Mac_2),
-
- %% Test case 4
- Case4Key = list_to_binary(lists:seq(1, 16#19)),
- Case4Data = binary:copy(<<16#cd>>, 50),
- Case4Exp = hexstr2bin("4c9007f4026250c6bc8414f9bf50c86c2d7235da"),
-
- ?line Case4Mac_1 = crypto:sha_mac(Case4Key, Case4Data),
- ?line Case4Mac_2 = crypto:hmac(sha, Case4Key, Case4Data),
- ?line m(Case4Exp, Case4Mac_1),
- ?line m(Case4Exp, Case4Mac_2),
-
- %% Test case 5
- Case5Key = binary:copy(<<16#0c>>, 20),
- Case5Data = "Test With Truncation",
- Case5Exp = hexstr2bin("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
- Case5Exp96 = hexstr2bin("4c1a03424b55e07fe7f27be1"),
-
- ?line Case5Mac_1 = crypto:sha_mac(Case5Key, Case5Data),
- ?line Case5Mac_2 = crypto:hmac(sha, Case5Key, Case5Data),
- ?line Case5Mac96_1 = crypto:sha_mac_96(Case5Key, Case5Data),
- ?line Case5Mac96_2 = crypto:hmac(sha, Case5Key, Case5Data, 12),
- ?line m(Case5Exp, Case5Mac_1),
- ?line m(Case5Exp, Case5Mac_2),
- ?line m(Case5Exp96, Case5Mac96_1),
- ?line m(Case5Exp96, Case5Mac96_2),
-
- %% Test case 6
- Case6Key = binary:copy(<<16#aa>>, 80),
- Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- Case6Exp = hexstr2bin("aa4ae5e15272d00e95705637ce8a3b55ed402112"),
-
- ?line Case6Mac_1 = crypto:sha_mac(Case6Key, Case6Data),
- ?line Case6Mac_2 = crypto:hmac(sha, Case6Key, Case6Data),
- ?line m(Case6Exp, Case6Mac_1),
- ?line m(Case6Exp, Case6Mac_2),
-
- %% Test case 7
- Case7Key = binary:copy(<<16#aa>>, 80),
- Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
- Case7Exp = hexstr2bin("e8e99d0f45237d786d6bbaa7965c7808bbff1a91"),
-
- ?line Case7Mac_1 = crypto:sha_mac(Case7Key, Case7Data),
- ?line Case7Mac_2 = crypto:hmac(sha, Case7Key, Case7Data),
- ?line m(Case7Exp, Case7Mac_1),
- ?line m(Case7Exp, Case7Mac_2).
-
-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_sha224(suite) ->
- [];
-hmac_rfc4231_sha224(Config) when is_list(Config) ->
- if_supported(sha224, fun() -> hmac_rfc4231_sha224_do() end).
-
-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
- 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, _, []) ->
+hash(_, [], []) ->
ok;
-hmac_rfc4231_cases_do(Hash, HashFun, [C|Cases], [D|CasesData]) ->
- hmac_rfc4231_case(Hash, HashFun, C, D),
- hmac_rfc4231_cases_do(Hash, HashFun, Cases, CasesData).
-
-hmac_update_md5_io(doc) ->
- ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:md5_mac." ];
-hmac_update_md5_io(suite) ->
- [];
-hmac_update_md5_io(Config) when is_list(Config) ->
- ?line Key = ["A fine speach", "by a fine man!"],
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(md5, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:md5_mac(Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-
-
-hmac_update_md5_n(doc) ->
- ["Generate a shortened MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:md5_mac." ];
-hmac_update_md5_n(suite) ->
- [];
-hmac_update_md5_n(Config) when is_list(Config) ->
- ?line Key = ["A fine speach", "by a fine man!"],
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(md5, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final_n(Ctx3, 12),
- ?line Exp = crypto:md5_mac_96(Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-%%
-%%
-ripemd160(doc) ->
- ["Generate RIPEMD160 message digests and check the result."];
-ripemd160(suite) ->
- [];
-ripemd160(Config) when is_list(Config) ->
- ?line m(crypto:hash(ripemd160,"abc"),
- hexstr2bin("8EB208F7E05D987A9B044A8E98C6B087F15A0BFC")),
- ?line m(crypto:hash(ripemd160,"abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
- "nlmnomnopnopq"),
- hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
-
-
-%%
-%%
-ripemd160_update(doc) ->
- ["Generate RIPEMD160 message digests by using ripemd160_init,"
- "ripemd160_update, and ripemd160_final and check the result."];
-ripemd160_update(suite) ->
- [];
-ripemd160_update(Config) when is_list(Config) ->
- ?line Ctx = crypto:hash_init(ripemd160),
- ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
- ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
- ?line m(crypto:hash_final(Ctx2),
- hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
-
-%%
-%%
-sha_update(doc) ->
- ["Generate SHA message digests by using sha_init, sha_update, and"
- "sha_final, and check the result. Examples are from FIPS-180-1."];
-sha_update(suite) ->
- [];
-sha_update(Config) when is_list(Config) ->
- ?line Ctx = crypto:sha_init(),
- ?line Ctx1 = crypto:sha_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
- ?line Ctx2 = crypto:sha_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
- ?line m(crypto:sha_final(Ctx2),
- hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")).
-
-%%
-%%
-sha256(doc) ->
- ["Generate SHA-256 message digests and check the result. Examples are "
- "from rfc-4634."];
-sha256(suite) ->
- [];
-sha256(Config) when is_list(Config) ->
- if_supported(sha256, fun() -> sha256_do() end).
-
-sha256_do() ->
- ?line m(crypto:sha256("abc"),
- hexstr2bin("BA7816BF8F01CFEA4141"
- "40DE5DAE2223B00361A396177A9CB410FF61F20015AD")),
- ?line m(crypto:sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
- "nlmnomnopnopq"),
- hexstr2bin("248D6A61D20638B8"
- "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
-
-%%
-%%
-sha256_update(doc) ->
- ["Generate SHA256 message digests by using sha256_init, sha256_update, and"
- "sha256_final, and check the result. Examples are from rfc-4634."];
-sha256_update(suite) ->
- [];
-sha256_update(Config) when is_list(Config) ->
- if_supported(sha256, fun() -> sha256_update_do() end).
-
-sha256_update_do() ->
- ?line Ctx = crypto:sha256_init(),
- ?line Ctx1 = crypto:sha256_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
- ?line Ctx2 = crypto:sha256_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
- ?line m(crypto:sha256_final(Ctx2),
- hexstr2bin("248D6A61D20638B8"
- "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
-
-
-%%
-%%
-sha512(doc) ->
- ["Generate SHA-512 message digests and check the result. Examples are "
- "from rfc-4634."];
-sha512(suite) ->
- [];
-sha512(Config) when is_list(Config) ->
- if_supported(sha512, fun() -> sha512_do() end).
-
-sha512_do() ->
- ?line m(crypto:sha512("abc"),
- hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
- "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
- "454D4423643CE80E2A9AC94FA54CA49F")),
- ?line m(crypto:sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
- "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
- hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
- "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
- "C7D329EEB6DD26545E96E55B874BE909")).
-
-%%
-%%
-sha512_update(doc) ->
- ["Generate SHA512 message digests by using sha512_init, sha512_update, and"
- "sha512_final, and check the result. Examples are from rfc=4634."];
-sha512_update(suite) ->
- [];
-sha512_update(Config) when is_list(Config) ->
- if_supported(sha512, fun() -> sha512_update_do() end).
-
-sha512_update_do() ->
- ?line Ctx = crypto:sha512_init(),
- ?line Ctx1 = crypto:sha512_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
- ?line Ctx2 = crypto:sha512_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
- ?line m(crypto:sha512_final(Ctx2),
- hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
- "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
- "C7D329EEB6DD26545E96E55B874BE909")).
-
-%%
-%%
-md5_mac(doc) ->
- ["Generate some HMACs, using MD5, and check the result. Examples are "
- "from RFC-2104."];
-md5_mac(suite) ->
- [];
-md5_mac(Config) when is_list(Config) ->
- ?line m(crypto:md5_mac(hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
- "Hi There"),
- hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")),
- ?line m(crypto:md5_mac(list_to_binary("Jefe"),
- "what do ya want for nothing?"),
- hexstr2bin("750c783e6ab0b503eaa86e310a5db738")),
- ?line m(crypto:md5_mac(hexstr2bin("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
- hexstr2bin("DDDDDDDDDDDDDDDDDDDD"
- "DDDDDDDDDDDDDDDDDDDD"
- "DDDDDDDDDDDDDDDDDDDD"
- "DDDDDDDDDDDDDDDDDDDD"
- "DDDDDDDDDDDDDDDDDDDD")),
- hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6")).
-
-%%
-%%
-md5_mac_io(doc) ->
- ["Generate some HMACs, using MD5, with Key an IO-list, and check the "
- "result. Examples are from RFC-2104."];
-md5_mac_io(suite) ->
- [];
-md5_mac_io(Config) when is_list(Config) ->
- ?line Key1 = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
- ?line {B11, B12} = split_binary(Key1, 4),
- ?line Key11 = [B11,binary_to_list(B12)],
- ?line m(crypto:md5_mac(Key11, "Hi There"),
- hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")).
-
-%%
-%%
-des_cbc(doc) ->
- "Encrypt and decrypt according to CBC DES. and check the result. "
- "Example are from FIPS-81.";
-des_cbc(suite) ->
- [];
-des_cbc(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain = "Now is the time for all ",
- ?line Cipher = crypto:des_cbc_encrypt(Key, IVec, Plain),
- ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
- "0f683788499a7c05f6")),
- ?line m(list_to_binary(Plain),
- crypto:des_cbc_decrypt(Key, IVec, Cipher)),
- ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
- ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec, Plain2),
- ?line m(Cipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9"
- "9484521388fa59ae67d58d2e77e86062733")),
- ?line m(list_to_binary(Plain2),
- crypto:des_cbc_decrypt(Key, IVec, Cipher2)).
-
-%%
-%%
-des_cbc_iter(doc) ->
- "Encrypt and decrypt according to CBC DES in two steps, and "
- "check the result. Example are from FIPS-81.";
-des_cbc_iter(suite) ->
- [];
-des_cbc_iter(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain1 = "Now is the time ",
- ?line Plain2 = "for all ",
- ?line Cipher1 = crypto:des_cbc_encrypt(Key, IVec, Plain1),
- ?line IVec2 = crypto:des_cbc_ivec(Cipher1),
- ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec2, Plain2),
- ?line Cipher = list_to_binary([Cipher1, Cipher2]),
- ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
- "0f683788499a7c05f6")).
-
-%%
-%%
-des_cfb(doc) ->
- "Encrypt and decrypt according to CFB DES. and check the result. "
- "Example is from FIPS-81.";
-des_cfb(suite) ->
- [];
-des_cfb(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain = "Now is the",
- ?line Cipher = crypto:des_cfb_encrypt(Key, IVec, Plain),
- ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")),
- ?line m(list_to_binary(Plain),
- crypto:des_cfb_decrypt(Key, IVec, Cipher)).
-
-%%
-%%
-des_cfb_iter(doc) ->
- "Encrypt and decrypt according to CFB DES in two steps, and "
- "check the result. Example is from FIPS-81.";
-des_cfb_iter(suite) ->
- [];
-des_cfb_iter(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain1 = "Now i",
- ?line Plain2 = "s the",
- ?line Cipher1 = crypto:des_cfb_encrypt(Key, IVec, Plain1),
- ?line IVec2 = crypto:des_cfb_ivec(IVec, Cipher1),
- ?line Cipher2 = crypto:des_cfb_encrypt(Key, IVec2, Plain2),
- ?line Cipher = list_to_binary([Cipher1, Cipher2]),
- ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")).
-
-%%
-%%
-des_ecb(doc) ->
- "Encrypt and decrypt according to ECB DES and check the result. "
- "Example are from FIPS-81.";
-des_ecb(suite) ->
- [];
-des_ecb(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line Cipher1 = crypto:des_ecb_encrypt(Key, "Now is t"),
- ?line m(Cipher1, hexstr2bin("3fa40e8a984d4815")),
- ?line Cipher2 = crypto:des_ecb_encrypt(Key, "he time "),
- ?line m(Cipher2, hexstr2bin("6a271787ab8883f9")),
- ?line Cipher3 = crypto:des_ecb_encrypt(Key, "for all "),
- ?line m(Cipher3, hexstr2bin("893d51ec4b563b53")),
- ?line Cipher4 = crypto:des_ecb_decrypt(Key, hexstr2bin("3fa40e8a984d4815")),
- ?line m(Cipher4, <<"Now is t">>),
- ?line Cipher5 = crypto:des_ecb_decrypt(Key, hexstr2bin("6a271787ab8883f9")),
- ?line m(Cipher5, <<"he time ">>),
- ?line Cipher6 = crypto:des_ecb_decrypt(Key, hexstr2bin("893d51ec4b563b53")),
- ?line m(Cipher6, <<"for all ">>).
-%%
-%%
-rc2_cbc(doc) ->
- "Encrypt and decrypt according to RC2 CBC and check the result. "
- "Example stripped out from public_key application test";
-rc2_cbc(Config) when is_list(Config) ->
-
- Key = <<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
- IV = <<72,91,135,182,25,42,35,210>>,
-
- Cipher = <<36,245,206,158,168,230,58,69,148,137,32,192,250,41,237,181,181,251, 192,2,175,135,177,171,57,30,111,117,159,149,15,28,88,158,28,81,28,115, 85,219,241,82,117,222,91,85,73,117,164,25,182,52,191,64,123,57,26,19, 211,27,253,31,194,219,231,104,247,240,172,130,119,21,225,154,101,247, 32,216,42,216,133,169,78,22,97,27,227,26,196,224,172,168,17,9,148,55, 203,91,252,40,61,226,236,221,215,160,78,63,13,181,68,57,196,241,185, 207, 116,129,152,237,60,139,247,153,27,146,161,246,222,98,185,222,152, 187,135, 236,86,34,7,110,91,230,173,34,160,242,202,222,121,127,181,140, 101,203,195, 190,88,250,86,147,127,87,72,126,171,16,71,47,110,248,88, 14,29,143,161,152, 129,236,148,22,152,186,208,119,70,8,174,193,203,100, 193,203,200,117,102,242, 134,142,96,125,135,200,217,190,76,117,50,70, 209,186,101,241,200,91,40,193,54, 90,195,38,47,59,197,38,234,86,223,16, 51,253,204,129,20,171,66,21,241,26,135,216, 196,114,110,91,15,53,40, 164,201,136,113,95,247,51,181,208,241,68,168,98,151,36, 155,72,24,57, 42,191,14,125,204,10,167,214,233,138,115,125,234,121,134,227,26,247, 77,200,117,110,117,111,168,156,206,67,159,149,189,173,150,193,91,199, 216,153,22, 189,137,185,89,160,13,131,132,58,109,28,110,246,252,251,14, 232,91,38,52,29,101,188,69,123,50,0,130,178,93,73,239,118,7,77,35,59, 253,10,159,45,86,142,37,78,232,48>>,
- Text = <<48,130,1,85,2,1,0,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,4,130,1,63,48,130, 1,59,2,1,0,2,65,0,222,187,252,44,9,214,27,173,162,169,70,47,36,34,78,84,204, 107,60,192,117,95,21,206,49,142,245,126,121,223,23,2,107,106,133,204,161,36, 40,2,114,69,4,93,242,5,42,50,154,47,154,211,209,123,120,161,5,114,173,155,34, 191,52,59,2,3,1,0,1,2,64,45,144,169,106,220,236,71,39,67,82,123,192,35,21,61, 143,13,110,150,180,12,142,210,40,39,109,70,125,132,51,6,66,159,134,112,85, 155,243,118,221,65,133,127,99,151,194,252,141,149,224,229,62,214,45,228,32, 184,85,67,14,228,161,184,161,2,33,0,255,202,240,131,130,57,49,224,115,255,83, 79,6,165,212,21,179,212,20,188,97,74,69,68,163,223,247,237,39,24,23,235,2,33, 0,222,234,48,36,33,23,219,45,59,136,55,245,143,29,165,48,255,131,207,146,131, 104,13,163,54,131,236,78,88,54,16,241,2,33,0,230,2,99,129,173,176,166,131, 241,106,143,76,9,107,70,41,121,185,228,39,124,200,159,62,216,169,5,180,111, 169,255,159,2,33,0,151,193,70,212,209,210,179,219,175,83,165,4,255,81,103,76, 92,39,24,0,222,132,208,3,244,241,10,198,171,54,227,129,2,32,43,250,20,31,16, 189,168,116,225,1,125,132,94,130,118,124,28,56,232,39,69,218,244,33,240,200, 205,9,215,101,35,135,7,7,7,7,7,7,7>>,
-
- Text = crypto:rc2_cbc_decrypt(Key, IV, Cipher),
- Cipher = crypto:rc2_cbc_encrypt(Key, IV, Text).
-
-%%
-%%
-des3_cbc(doc) ->
- "Encrypt and decrypt according to CBC 3DES, and check the result.";
-des3_cbc(suite) ->
- [];
-des3_cbc(Config) when is_list(Config) ->
- ?line Key1 = hexstr2bin("0123456789abcdef"),
- ?line Key2 = hexstr2bin("fedcba9876543210"),
- ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain = "Now is the time for all ",
- ?line Cipher = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain),
- ?line m(Cipher, hexstr2bin("8a2667ee5577267cd9b1af2c5a0480"
- "0bac1ae66970fb2b89")),
- ?line m(list_to_binary(Plain),
- crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher)),
- ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
- ?line Cipher2 = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain2),
- ?line m(Cipher2, hexstr2bin("eb33ec6ede2c8e90f6877e77b95d5"
- "4c83cee22907f7f0041ca1b7abe202bfafe")),
- ?line m(list_to_binary(Plain2),
- crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher2)),
-
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line DESCipher = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain),
- ?line m(DESCipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
- "0f683788499a7c05f6")),
- ?line m(list_to_binary(Plain),
- crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher)),
- ?line DESCipher2 = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain2),
- ?line m(DESCipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9"
- "9484521388fa59ae67d58d2e77e86062733")),
- ?line m(list_to_binary(Plain2),
- crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher2)).
-
-%%
-%%
-des3_cfb(doc) ->
- "Encrypt and decrypt according to CFB 3DES, and check the result.";
-des3_cfb(suite) ->
- [];
-des3_cfb(Config) when is_list(Config) ->
- case openssl_version() of
- V when V < 16#90705F -> {skipped,"OpenSSL version too old"};
- _ -> des3_cfb_do()
+hash(Type, [Msg | RestMsg], [Digest| RestDigest]) ->
+ case crypto:hash(Type, Msg) of
+ Digest ->
+ hash(Type, RestMsg, RestDigest);
+ Other ->
+ ct:fail({{crypto, hash, [Type, Msg]}, {expected, Digest}, {got, Other}})
end.
-des3_cfb_do() ->
- ?line Key1 = hexstr2bin("0123456789abcdef"),
- ?line Key2 = hexstr2bin("fedcba9876543210"),
- ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain = "Now is the time for all ",
- ?line Cipher = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain),
- ?line m(Cipher, hexstr2bin("fc0ba7a20646ba53cc8bff263f0937"
- "1deab42a00666db02c")),
- ?line m(list_to_binary(Plain),
- crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher)),
- ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
- ?line Cipher2 = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain2),
- ?line m(Cipher2, hexstr2bin("8582c59ac01897422632c0accb66c"
- "e413f5efab838fce7e41e2ba67705bad5bc")),
- ?line m(list_to_binary(Plain2),
- crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher2)).
-
-%%
-%%
-aes_cfb(doc) ->
- "Encrypt and decrypt according to AES CFB 128 bit and check "
- "the result. Example are from NIST SP 800-38A.";
-
-aes_cfb(suite) ->
- [];
-aes_cfb(Config) when is_list(Config) ->
-
-%% Sample data from NIST Spec.Publ. 800-38A
-%% F.3.13 CFB128-AES128.Encrypt
-%% Key 2b7e151628aed2a6abf7158809cf4f3c
-%% IV 000102030405060708090a0b0c0d0e0f
-%% Segment #1
-%% Input Block 000102030405060708090a0b0c0d0e0f
-%% Output Block 50fe67cc996d32b6da0937e99bafec60
-%% Plaintext 6bc1bee22e409f96e93d7e117393172a
-%% Ciphertext 3b3fd92eb72dad20333449f8e83cfb4a
-%% Segment #2
-%% Input Block 3b3fd92eb72dad20333449f8e83cfb4a
-%% Output Block 668bcf60beb005a35354a201dab36bda
-%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
-%% Ciphertext c8a64537a0b3a93fcde3cdad9f1ce58b
-%% Segment #3
-%% Input Block c8a64537a0b3a93fcde3cdad9f1ce58b
-%% Output Block 16bd032100975551547b4de89daea630
-%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
-%% Ciphertext 26751f67a3cbb140b1808cf187a4f4df
-%% Segment #4
-%% Input Block 26751f67a3cbb140b1808cf187a4f4df
-%% Output Block 36d42170a312871947ef8714799bc5f6
-%% Plaintext f69f2445df4f9b17ad2b417be66c3710
-%% Ciphertext c04b05357c5d1c0eeac4c66f9ff7f2e6
-
- ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
- ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"),
- ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"),
- ?line Cipher = hexstr2bin("3b3fd92eb72dad20333449f8e83cfb4a"),
-
- %% Try all prefixes of plain and cipher.
- aes_cfb_do(byte_size(Plain), Plain, Cipher, Key, IVec).
-
-aes_cfb_do(N, Plain, Cipher, Key, IVec) when N >= 0 ->
- <<P:N/binary, _/binary>> = Plain,
- <<C:N/binary, _/binary>> = Cipher,
- ?line C = crypto:aes_cfb_128_encrypt(Key, IVec, P),
- ?line P = crypto:aes_cfb_128_decrypt(Key, IVec, C),
- aes_cfb_do(N-1, Plain, Cipher, Key, IVec);
-aes_cfb_do(_, _, _, _, _) -> ok.
-
-
-%%
-%%
-aes_cbc(doc) ->
- "Encrypt and decrypt according to AES CBC 128 bit. and check the result. "
- "Example are from NIST SP 800-38A.";
-
-aes_cbc(suite) ->
- [];
-aes_cbc(Config) when is_list(Config) ->
-
-%% Sample data from NIST Spec.Publ. 800-38A
-%% F.2.1 CBC-AES128.Encrypt
-%% Key 2b7e151628aed2a6abf7158809cf4f3c
-%% IV 000102030405060708090a0b0c0d0e0f
-%% Block #1
-%% Plaintext 6bc1bee22e409f96e93d7e117393172a
-%% Input Block 6bc0bce12a459991e134741a7f9e1925
-%% Output Block 7649abac8119b246cee98e9b12e9197d
-%% Ciphertext 7649abac8119b246cee98e9b12e9197d
-%% Block #2
-%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
-%% Input Block d86421fb9f1a1eda505ee1375746972c
-%% Output Block 5086cb9b507219ee95db113a917678b2
-%% Ciphertext 5086cb9b507219ee95db113a917678b2
-%% Block #3
-%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
-%% Input Block 604ed7ddf32efdff7020d0238b7c2a5d
-%% Output Block 73bed6b8e3c1743b7116e69e22229516
-%% Ciphertext 73bed6b8e3c1743b7116e69e22229516
-%% Block #4
-%% Plaintext f69f2445df4f9b17ad2b417be66c3710
-%% Input Block 8521f2fd3c8eef2cdc3da7e5c44ea206
-%% Output Block 3ff1caa1681fac09120eca307586e1a7
-%% Ciphertext 3ff1caa1681fac09120eca307586e1a7
-%%
-%% F.2.2 CBC-AES128.Decrypt
-%% Key 2b7e151628aed2a6abf7158809cf4f3c
-%% IV 000102030405060708090a0b0c0d0e0f
- %% Block #1
-%% Ciphertext 7649abac8119b246cee98e9b12e9197d
-%% Input Block 7649abac8119b246cee98e9b12e9197d
-%% Output Block 6bc0bce12a459991e134741a7f9e1925
-%% Plaintext 6bc1bee22e409f96e93d7e117393172a
-%% Block #2
-%% Ciphertext 5086cb9b507219ee95db113a917678b2
-%% Input Block 5086cb9b507219ee95db113a917678b2
-%% Output Block d86421fb9f1a1eda505ee1375746972c
-%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
-%% Block #3
-%% Ciphertext 73bed6b8e3c1743b7116e69e22229516
-%% Input Block 73bed6b8e3c1743b7116e69e22229516
-%% Output Block 604ed7ddf32efdff7020d0238b7c2a5d
-%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
-%% Block #4
-%% Ciphertext 3ff1caa1681fac09120eca307586e1a7
-%% Input Block 3ff1caa1681fac09120eca307586e1a7
-%% Output Block 8521f2fd3c8eef2cdc3da7e5c44ea206
-%% Plaintext f69f2445df4f9b17ad2b417be66c3710
-
- ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
- ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"),
- ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"),
- ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain),
- ?line m(Cipher, hexstr2bin("7649abac8119b246cee98e9b12e9197d")),
- ?line m(Plain,
- crypto:aes_cbc_128_decrypt(Key, IVec, Cipher)).
-
-aes_cbc_iter(doc) ->
- "Encrypt and decrypt according to CBC AES in steps";
-aes_cbc_iter(suite) -> [];
-aes_cbc_iter(Config) when is_list(Config) ->
- Key = list_to_binary(lists:seq(255,256-16*17,-17)),
- IVec = list_to_binary(lists:seq(1,16*7,7)),
- Plain = <<"One, two, three o'clock, four o'clock, rock"
- "Five, six, seven o'clock, eight o'clock, rock"
- "Nine, ten, eleven o'clock, twelve o'clock, rock"
- "We're gonna rock around the clock tonight">>,
- ?line 0 = size(Plain) rem 16,
-
- ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain),
- ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Cipher),
-
- ?line Cipher = aes_cbc_encrypt_iter(Key,IVec,Plain,<<>>),
- ?line Plain = aes_cbc_decrypt_iter(Key,IVec,Cipher,<<>>),
- ok.
+hash_increment(Type, Increments, Digest) ->
+ State = crypto:hash_init(Type),
+ case hash_increment(State, Increments) of
+ Digest ->
+ ok;
+ Other ->
+ ct:fail({{crypto, "hash_init/update/final", [Type, Increments]}, {expected, Digest}, {got, Other}})
+ end.
-aes_cbc_encrypt_iter(_,_,<<>>, Acc) ->
- Acc;
-aes_cbc_encrypt_iter(Key,IVec,Data, Acc) ->
- Bytes = 16 * (1 + size(Data) div (16*3)),
- <<Chunk:Bytes/binary, Rest/binary>> = Data,
- %%io:format("encrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]),
- ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Chunk),
- ?line IVec2 = crypto:aes_cbc_ivec(Cipher),
- aes_cbc_encrypt_iter(Key,IVec2,Rest, <<Acc/binary, Cipher/binary>>).
-
-aes_cbc_decrypt_iter(_,_,<<>>, Acc) ->
- Acc;
-aes_cbc_decrypt_iter(Key,IVec,Data, Acc) ->
- Bytes = 16 * (1 + size(Data) div (16*5)),
- <<Chunk:Bytes/binary, Rest/binary>> = Data,
- %%io:format("decrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]),
- ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Chunk),
- ?line IVec2 = crypto:aes_cbc_ivec(Chunk),
- aes_cbc_decrypt_iter(Key,IVec2,Rest, <<Acc/binary, Plain/binary>>).
-
-
-aes_ctr(doc) -> "CTR";
-aes_ctr(Config) when is_list(Config) ->
- %% Sample data from NIST Spec.Publ. 800-38A
- %% F.5.1 CTR-AES128.Encrypt
- Key128 = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
- Samples128 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- "6bc1bee22e409f96e93d7e117393172a", % Plaintext
- "874d6191b620e3261bef6864990db6ce"},% Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- "ae2d8a571e03ac9c9eb76fac45af8e51",
- "9806f66b7970fdff8617187bb9fffdff"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- "30c81c46a35ce411e5fbc1191a0a52ef",
- "5ae4df3edbd5d35e5b4f09020db03eab"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- "f69f2445df4f9b17ad2b417be66c3710",
- "1e031dda2fbe03d1792170a0f3009cee"}],
- lists:foreach(fun(S) -> aes_ctr_do(Key128,S) end, Samples128),
-
- %% F.5.3 CTR-AES192.Encrypt
- Key192 = hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
- Samples192 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- "6bc1bee22e409f96e93d7e117393172a", % Plaintext
- "1abc932417521ca24f2b0459fe7e6e0b"},% Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- "ae2d8a571e03ac9c9eb76fac45af8e51",
- "090339ec0aa6faefd5ccc2c6f4ce8e94"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- "30c81c46a35ce411e5fbc1191a0a52ef",
- "1e36b26bd1ebc670d1bd1d665620abf7"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- "f69f2445df4f9b17ad2b417be66c3710",
- "4f78a7f6d29809585a97daec58c6b050"}],
- lists:foreach(fun(S) -> aes_ctr_do(Key192,S) end, Samples192),
-
- %% F.5.5 CTR-AES256.Encrypt
- Key256 = hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
- Samples256 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- "6bc1bee22e409f96e93d7e117393172a", % Plaintext
- "601ec313775789a5b7a7f504bbf3d228"},% Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- "ae2d8a571e03ac9c9eb76fac45af8e51",
- "f443e3ca4d62b59aca84e990cacaf5c5"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- "30c81c46a35ce411e5fbc1191a0a52ef",
- "2b0930daa23de94ce87017ba2d84988d"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- "f69f2445df4f9b17ad2b417be66c3710",
- "dfc9c58db67aada613c2dd08457941a6"}],
- lists:foreach(fun(S) -> aes_ctr_do(Key256,S) end, Samples256).
-
-
-aes_ctr_do(Key,{IVec, Plain, Cipher}) ->
- ?line I = hexstr2bin(IVec),
- ?line P = hexstr2bin(Plain),
- ?line C = crypto:aes_ctr_encrypt(Key, I, P),
- ?line m(C, hexstr2bin(Cipher)),
- ?line m(P, crypto:aes_ctr_decrypt(Key, I, C)).
-
-aes_ctr_stream(doc) -> "CTR Streaming";
-aes_ctr_stream(Config) when is_list(Config) ->
- %% Sample data from NIST Spec.Publ. 800-38A
- %% F.5.1 CTR-AES128.Encrypt
- Key128 = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
- Samples128 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- ["6bc1bee22e409f", "96e93d7e117393172a"], % Plaintext
- ["874d6191b620e3261bef6864990db6ce"]}, % Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- ["ae2d8a57", "1e03ac9c", "9eb76fac", "45af8e51"],
- ["9806f66b7970fdff","8617187bb9fffdff"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- ["30c81c46a35c", "e411e5fbc119", "1a0a52ef"],
- ["5ae4df3e","dbd5d3","5e5b4f0902","0db03eab"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- ["f69f2445df4f9b17ad2b417be66c3710"],
- ["1e031dda2fbe","03d1792170a0","f3009cee"]}],
- lists:foreach(fun(S) -> aes_ctr_stream_do(Key128,S) end, Samples128),
-
- %% F.5.3 CTR-AES192.Encrypt
- Key192 = hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
- Samples192 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- ["6bc1bee22e409f96e93d7e117393172a"], % Plaintext
- ["1abc9324","17521c","a24f2b04","59fe7e6e0b"]}, % Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- ["ae2d8a57", "1e03ac9c9eb76fac", "45af8e51"],
- ["090339ec0aa6faefd5ccc2c6f4ce8e94"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- ["30c81c46a35ce411", "e5fbc1191a0a52ef"],
- ["1e36b26bd1","ebc670d1bd1d","665620abf7"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- ["f69f2445", "df4f9b17ad", "2b417be6", "6c3710"],
- ["4f78a7f6d2980958","5a97daec58c6b050"]}],
- lists:foreach(fun(S) -> aes_ctr_stream_do(Key192,S) end, Samples192),
-
- %% F.5.5 CTR-AES256.Encrypt
- Key256 = hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
- Samples256 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- ["6bc1bee22e409f96", "e93d7e117393172a"], % Plaintext
- ["601ec313775789", "a5b7a7f504bbf3d228"]}, % Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- ["ae2d8a571e03ac9c9eb76fac45af8e51"],
- ["f443e3ca","4d62b59aca84","e990cacaf5c5"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- ["30c81c46","a35ce411","e5fbc119","1a0a52ef"],
- ["2b0930daa23de94ce87017ba2d84988d"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- ["f69f2445df4f","9b17ad2b41","7be66c3710"],
- ["dfc9c5","8db67aada6","13c2dd08","457941a6"]}],
- lists:foreach(fun(S) -> aes_ctr_stream_do(Key256,S) end, Samples256).
-
-
-aes_ctr_stream_do(Key,{IVec, PlainList, CipherList}) ->
- ?line I = hexstr2bin(IVec),
- ?line S = crypto:aes_ctr_stream_init(Key, I),
- ?line C = aes_ctr_stream_do_iter(
- S, PlainList, [],
- fun(S2,P) -> crypto:aes_ctr_stream_encrypt(S2, P) end),
- ?line m(C, hexstr2bin(lists:flatten(CipherList))),
- ?line P = aes_ctr_stream_do_iter(
- S, CipherList, [],
- fun(S2,C2) -> crypto:aes_ctr_stream_decrypt(S2, C2) end),
- ?line m(P, hexstr2bin(lists:flatten(PlainList))).
-
-aes_ctr_stream_do_iter(_State, [], Acc, _CipherFun) ->
- iolist_to_binary(lists:reverse(Acc));
-aes_ctr_stream_do_iter(State, [Plain|Rest], Acc, CipherFun) ->
- ?line P = hexstr2bin(Plain),
- ?line {S2, C} = CipherFun(State, P),
- aes_ctr_stream_do_iter(S2, Rest, [C | Acc], CipherFun).
+hash_increment(State, []) ->
+ crypto:hash_final(State);
+hash_increment(State0, [Increment | Rest]) ->
+ State = crypto:hash_update(State0, Increment),
+ hash_increment(State, Rest).
-%%
-%%
-mod_exp_test(doc) ->
- "mod_exp testing (A ^ M % P with bignums)";
-mod_exp_test(suite) ->
- [];
-mod_exp_test(Config) when is_list(Config) ->
- mod_exp_aux_test(2, 5, 10, 8).
-
-mod_exp_aux_test(_, _, _, 0) ->
+hmac(_, [],[],[]) ->
ok;
-mod_exp_aux_test(B, E, M, N) ->
- ?line R1 = crypto:mod_exp(B, E, M),
- ?line R2 = ipow(B, E, M),
- ?line m(R1, R2),
- ?line mod_exp_aux_test(B, E*E+1, M*M+1, N-1).
-
-%%
-%%
-rand_uniform_test(doc) ->
- "rand_uniform and random_bytes testing";
-rand_uniform_test(suite) ->
- [];
-rand_uniform_test(Config) when is_list(Config) ->
- rand_uniform_aux_test(10),
- ?line 10 = size(crypto:rand_bytes(10)).
-
-rand_uniform_aux_test(0) ->
- ok;
-rand_uniform_aux_test(N) ->
- ?line L = N*1000,
- ?line H = N*100000+1,
- ?line crypto_rand_uniform(L, H),
- ?line crypto_rand_uniform(-L, L),
- ?line crypto_rand_uniform(-H, -L),
- ?line crypto_rand_uniform(-H, L),
- ?line rand_uniform_aux_test(N-1).
-
-crypto_rand_uniform(L,H) ->
- ?line R1 = crypto:rand_uniform(L, H),
- ?line t(R1 >= L),
- ?line t(R1 < H).
+hmac(sha = Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
+ case crypto:hmac(Type, Key, Data, 20) of
+ Expected ->
+ ok;
+ Other ->
+ ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
+ end,
+ hmac(Type, Keys, Rest, Expects);
+
+hmac(Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
+ case crypto:hmac(Type, Key, Data, 16) of
+ Expected ->
+ ok;
+ Other ->
+ ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
+ end,
+ hmac(Type, Keys, Rest, Expects);
+
+hmac(Type, [Key | Keys], [Data| Rest], [Expected | Expects]) ->
+ case crypto:hmac(Type, Key, Data) of
+ Expected ->
+ ok;
+ Other ->
+ ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
+ end,
+ hmac(Type, Keys, Rest, Expects).
+
+hmac_increment(Type) ->
+ Key = hmac_key(Type),
+ Increments = hmac_inc(Type),
+ Expected = crypto:hmac(Type, Key, lists:flatten(Increments)),
+ State = crypto:hmac_init(Type, Key),
+ case hmac_increment(State, Increments) of
+ Expected ->
+ ok;
+ Other ->
+ ct:fail({{crypto, "hmac_init/update/final", [Type, Increments]}, {expected, Expected}, {got, Other}})
+ end.
+hmac_increment(State, []) ->
+ crypto:hmac_final(State);
+hmac_increment(State0, [Increment | Rest]) ->
+ State = crypto:hmac_update(State0, Increment),
+ hmac_increment(State, Rest).
+
+block_cipher({Type, Key, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ CipherText = crypto:block_encrypt(Type, Key, PlainText),
+ case crypto:block_decrypt(Type, Key, CipherText) of
+ Plain ->
+ ok;
+ Other ->
+ ct:fail({{crypto, block_decrypt, [Type, Key, CipherText]}, {expected, Plain}, {got, Other}})
+ end;
+
+block_cipher({Type, Key, IV, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ CipherText = crypto:block_encrypt(Type, Key, IV, PlainText),
+ case crypto:block_decrypt(Type, Key, IV, CipherText) of
+ Plain ->
+ ok;
+ Other ->
+ ct:fail({{crypto, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other}})
+ end.
-%%
-%%
-strong_rand_test(doc) ->
- "strong_rand_mpint and strong_random_bytes testing";
-strong_rand_test(suite) ->
- [];
-strong_rand_test(Config) when is_list(Config) ->
- strong_rand_aux_test(180),
- ?line 10 = byte_size(crypto:strong_rand_bytes(10)).
-
-strong_rand_aux_test(0) ->
- ?line t(crypto:strong_rand_mpint(0,0,0) =:= <<0,0,0,0>>),
+block_cipher_increment({Type, Key, IV, PlainTexts}) when Type == des_cbc;
+ Type == des3_cbc;
+ Type == aes_cbc;
+ Type == des_cbf
+ ->
+ block_cipher_increment(Type, Key, IV, IV, PlainTexts, iolist_to_binary(PlainTexts), []);
+block_cipher_increment({_Type, _, _, _}) ->
ok;
-strong_rand_aux_test(1) ->
- ?line t(crypto:erlint(crypto:strong_rand_mpint(1,0,1)) =:= 1),
- ?line strong_rand_aux_test(0);
-strong_rand_aux_test(N) ->
- ?line t(sru_length(crypto:strong_rand_mpint(N,-1,0)) =< N),
- ?line t(sru_length(crypto:strong_rand_mpint(N,0,0)) =:= N),
- ?line t(crypto:erlint(crypto:strong_rand_mpint(N,0,1)) band 1 =:= 1),
- ?line t(crypto:erlint(crypto:strong_rand_mpint(N,1,0)) bsr (N - 2) =:= 2#11),
- ?line strong_rand_aux_test(N-1).
-
-sru_length(Mpint) ->
- I = crypto:erlint(Mpint),
- length(erlang:integer_to_list(I, 2)).
-
-%%
-%%
-%%
-%%
-rsa_verify_test(doc) ->
- "rsa_verify testing (A ^ M % P with bignums)";
-rsa_verify_test(suite) ->
- [];
-rsa_verify_test(Config) when is_list(Config) ->
- ?line H = <<178,28,54,104,36,80,144,66,140,201,135,17,36,97,114,124,
- 194,164,172,147>>,
- ?line SigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70,
- 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241,
- 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23,
- 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76,
- 115,34,107,227,151,47,80,185,143,85,202,55,245,163,226,26,
- 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180,
- 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14,
- 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>,
- ?line BadSigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70,
- 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241,
- 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23,
- 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76,
- 115,107,34,227,151,47,80,185,143,85,202,55,245,163,226,26,
- 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180,
- 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14,
- 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>,
- ?line E = <<35>>,
- ?line N = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10,
- 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193,
- 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6,
- 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1,
- 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123,
- 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50,
- 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73,
- 76,89,40,33,147,208,189,76,98,24,61,8,10,110,165,119,165>>,
- ?line Nbad = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10,
- 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193,
- 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6,
- 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1,
- 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123,
- 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50,
- 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73,
- 76,89,40,33,147,189,208,76,98,24,61,8,10,110,165,119,165>>,
- ?line Ebad = <<77>>,
- ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
- [sized_binary(E), sized_binary(N)]), true),
- ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
- [sized_binary(Ebad), sized_binary(N)]), false),
- ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
- [sized_binary(E), sized_binary(Nbad)]), false),
- ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(BadSigBlob),
- [sized_binary(E), sized_binary(N)]), false).
-
-%%
-%%
-dsa_verify_test(doc) ->
- "dsa_verify testing (A ^ M % P with bignums)";
-dsa_verify_test(suite) ->
- [];
-dsa_verify_test(Config) when is_list(Config) ->
- ?line Msg = <<48,130,2,245,160,3,2,1,2,2,1,1,48,9,6,7,42,134,72,206,56,4,3,48,
- 58,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3,85,4,10,19,17,
- 84,101,115,116,32,67,101,114,116,105,102,105,99,97,116,101,115,49,
- 15,48,13,6,3,85,4,3,19,6,68,83,65,32,67,65,48,30,23,13,48,49,48,
- 52,49,57,49,52,53,55,50,48,90,23,13,49,49,48,52,49,57,49,52,53,55,
- 50,48,90,48,93,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3,
- 85,4,10,19,17,84,101,115,116,32,67,101,114,116,105,102,105,99,97,
- 116,101,115,49,50,48,48,6,3,85,4,3,19,41,86,97,108,105,100,32,68,
- 83,65,32,83,105,103,110,97,116,117,114,101,115,32,69,69,32,67,101,
- 114,116,105,102,105,99,97,116,101,32,84,101,115,116,52,48,130,1,
- 182,48,130,1,43,6,7,42,134,72,206,56,4,1,48,130,1,30,2,129,129,0,
- 228,139,175,64,140,21,215,61,124,238,3,150,18,104,193,32,5,232,23,
- 202,158,116,101,75,154,84,151,42,120,51,218,165,197,114,234,52,
- 179,148,104,66,213,27,253,119,240,168,66,158,100,147,144,182,194,
- 2,49,70,19,122,3,105,204,152,45,86,157,94,35,95,40,191,173,127,15,
- 208,105,149,98,92,26,7,42,94,140,115,73,126,253,18,34,142,85,229,
- 86,233,174,114,41,150,135,8,39,215,119,67,240,134,184,9,10,27,20,
- 165,230,3,230,69,121,77,233,250,83,95,193,9,189,126,197,195,2,21,
- 0,128,63,228,252,243,76,229,62,203,15,23,10,42,84,108,208,103,108,
- 13,59,2,129,128,102,212,22,138,32,173,254,209,50,159,165,127,167,
- 179,208,234,119,63,235,108,162,228,41,216,216,188,33,221,154,247,
- 204,229,180,119,77,223,236,218,162,140,156,117,18,90,31,254,102,
- 211,17,194,239,132,67,236,169,136,110,76,186,76,63,53,150,199,103,
- 252,153,189,15,153,41,19,145,78,216,2,174,254,107,175,80,86,170,
- 47,30,181,42,200,238,34,71,37,120,107,33,221,20,63,206,240,16,129,
- 247,150,29,156,65,187,94,68,146,93,46,198,30,184,205,105,200,143,
- 63,59,62,208,79,162,206,217,3,129,132,0,2,129,128,15,83,40,172,56,
- 47,61,243,17,97,65,195,61,167,214,122,247,246,1,50,211,33,113,16,
- 20,213,195,62,77,235,25,162,140,175,158,8,61,65,10,255,204,162,71,
- 130,122,86,161,163,253,236,178,139,183,57,181,202,160,25,133,130,
- 155,150,104,168,187,107,186,144,164,225,173,101,182,68,49,210,30,
- 34,47,83,65,79,250,156,248,47,232,44,67,36,22,126,43,216,100,247,
- 100,250,240,121,72,29,185,2,109,144,54,204,235,54,15,242,57,171,
- 125,39,236,247,71,111,221,51,196,126,77,238,36,87,163,107,48,105,
- 48,29,6,3,85,29,14,4,22,4,20,179,51,215,81,162,4,13,68,251,157,64,
- 241,18,98,113,176,83,246,105,13,48,31,6,3,85,29,35,4,24,48,22,128,
- 20,116,21,213,36,28,189,94,101,136,31,225,139,9,126,127,234,25,72,
- 78,97,48,23,6,3,85,29,32,4,16,48,14,48,12,6,10,96,134,72,1,101,3,
- 2,1,48,1,48,14,6,3,85,29,15,1,1,255,4,4,3,2,6,192>>,
-
- ?line SigBlob = <<48,45,2,21,0,140,167,200,210,153,212,64,155,249,33,146,104,243,
- 39,38,9,115,162,89,24,2,20,76,254,31,128,187,48,128,215,216,
- 112,198,78,118,160,217,157,180,246,64,234>>,
- ?line P_p = 157224271412839155721795253728878055347359513988016145491388196653004661857517720927482198111104095793441029858267073789634147217022008635826863307553453131345099940951090826856271796188522037524757740796268675508118348391218066949174594918958269259937813776150149068811425194955973128428675945283593831134219,
- ?line Q_p = 1181895316321540581845959276009400765315408342791,
- ?line G_p = 143872196713149000950547166575757355261637863805587906227228163275557375159769599033632918292482002186641475268486598023281100659643528846513898847919251032731261718358900479488287933293278745715922865499005559197328388506945134386346185262919258658109015074718441639029135304654725637911172671711310801418648,
-
- ?line Key = 12603618348903387232593303690286336220738319446775939686476278478034365380027994899970214309288018488811754534229198764622077544117034174589418477472887827980332636062691833965078594576024299807057520016043084384987871640003684704483975314128362610573625803532737054022545217931847268776098203204571431581966,
-
- ValidKey = [crypto:mpint(P_p),
- crypto:mpint(Q_p),
- crypto:mpint(G_p),
- crypto:mpint(Key)
- ],
-
- ?line m(my_dss_verify(sized_binary(Msg), sized_binary(SigBlob),
- ValidKey), true),
-
- BadMsg = one_bit_wrong(Msg),
- ?line m(my_dss_verify(sized_binary(BadMsg), sized_binary(SigBlob),
- ValidKey), false),
- BadSig = one_bit_wrong(SigBlob),
- ?line m(my_dss_verify(sized_binary(Msg), sized_binary(BadSig),
- ValidKey), false),
- SizeErr = size(SigBlob) - 13,
-
- BadArg = (catch my_dss_verify(sized_binary(Msg), <<SizeErr:32, SigBlob/binary>>,
- ValidKey)),
- ?line m(element(1,element(2,BadArg)), badarg),
-
- InValidKey = [crypto:mpint(P_p),
- crypto:mpint(Q_p),
- crypto:mpint(G_p),
- crypto:mpint(Key+17)
- ],
-
- ?line m(my_dss_verify(sized_binary(Msg), sized_binary(SigBlob),
- InValidKey), false).
-
-
-one_bit_wrong(List) when is_list(List) ->
- lists:map(fun(Bin) -> one_bit_wrong(Bin) end, List);
-one_bit_wrong(Bin) ->
- Half = size(Bin) div 2,
- <<First:Half/binary, Byte:8, Last/binary>> = Bin,
- <<First/binary, (Byte+1):8, Last/binary>>.
-
-
-%%
-%% Sign tests
-
-rsa_sign_test(doc) ->
- "rsa_sign testing";
-rsa_sign_test(suite) ->
- [];
-rsa_sign_test(Config) when is_list(Config) ->
- PubEx = 65537,
- PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
- Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
- Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
- "09812312908312378623487263487623412039812 huagasd">>,
-
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
- ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true),
-
- ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true),
-
- ?line m(Sig1 =:= Sig2, false),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false),
- ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true),
-
+block_cipher_increment({_,_,_}) ->
ok.
-
-rsa_sign_hash_test(doc) ->
- "rsa_sign_hash testing";
-rsa_sign_hash_test(suite) ->
- [];
-rsa_sign_hash_test(Config) when is_list(Config) ->
- PubEx = 65537,
- PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
- Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
- Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
- "09812312908312378623487263487623412039812 huagasd">>,
-
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
- MD5 = crypto:md5(sized_binary(Msg)),
- SHA = crypto:sha(sized_binary(Msg)),
- ?line Sig1 = crypto:rsa_sign(sha, {digest,SHA}, PrivKey),
- ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig1),PubKey), true),
-
- ?line Sig2 = crypto:rsa_sign(md5, {digest,MD5}, PrivKey),
- ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig2),PubKey), true),
-
- ?line m(Sig1 =:= Sig2, false),
- ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig1),PubKey), false),
- ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig2),PubKey), false),
+block_cipher_increment(Type, Key, IV0, _IV, [], Plain, Acc) ->
+ CipherText = iolist_to_binary(lists:reverse(Acc)),
+ case crypto:block_decrypt(Type, Key, IV0, CipherText) of
+ Plain ->
+ ok;
+ Other ->
+ ct:fail({{crypto, block_decrypt, [Type, Key, IV0, CipherText]}, {expected, Plain}, {got, Other}})
+ end;
+block_cipher_increment(Type, Key, IV0, IV, [PlainText | PlainTexts], Plain, Acc) ->
+ CipherText = crypto:block_encrypt(Type, Key, IV, PlainText),
+ NextIV = crypto:next_iv(Type, CipherText),
+ block_cipher_increment(Type, Key, IV0, NextIV, PlainTexts, Plain, [CipherText | Acc]).
+
+stream_cipher({Type, Key, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ State = crypto:stream_init(Type, Key),
+ {_, CipherText} = crypto:stream_encrypt(State, PlainText),
+ case crypto:stream_decrypt(State, CipherText) of
+ {_, Plain} ->
+ ok;
+ Other ->
+ ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other}})
+ end;
+stream_cipher({Type, Key, IV, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ State = crypto:stream_init(Type, Key, IV),
+ {_, CipherText} = crypto:stream_encrypt(State, PlainText),
+ case crypto:stream_decrypt(State, CipherText) of
+ {_, Plain} ->
+ ok;
+ Other ->
+ ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other}})
+ end.
- ok.
+stream_cipher_incment({Type, Key, PlainTexts}) ->
+ State = crypto:stream_init(Type, Key),
+ stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts));
+stream_cipher_incment({Type, Key, IV, PlainTexts}) ->
+ State = crypto:stream_init(Type, Key, IV),
+ stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts)).
+
+stream_cipher_incment(_State, OrigState, [], Acc, Plain) ->
+ CipherText = iolist_to_binary(lists:reverse(Acc)),
+ case crypto:stream_decrypt(OrigState, CipherText) of
+ {_, Plain} ->
+ ok;
+ Other ->
+ ct:fail({{crypto, stream_decrypt, [OrigState, CipherText]}, {expected, Plain}, {got, Other}})
+ end;
+stream_cipher_incment(State0, OrigState, [PlainText | PlainTexts], Acc, Plain) ->
+ {State, CipherText} = crypto:stream_encrypt(State0, PlainText),
+ stream_cipher_incment(State, OrigState, PlainTexts, [CipherText | Acc], Plain).
+
+do_sign_verify({Type, Hash, Public, Private, Msg}) ->
+ Signature = crypto:sign(Type, Hash, Msg, Private),
+ case crypto:verify(Type, Hash, Msg, Signature, Public) of
+ true ->
+ negative_verify(Type, Hash, Msg, <<10,20>>, Public);
+ false ->
+ ct:fail({{crypto, verify, [Type, Hash, Msg, Signature, Public]}})
+ end.
-dsa_sign_test(doc) ->
- "dsa_sign testing";
-dsa_sign_test(suite) ->
- [];
-dsa_sign_test(Config) when is_list(Config) ->
- Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
- "09812312908312378623487263487623412039812 huagasd">>,
-
- PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978,
- PrivKey = _X = 441502407453038284293378221372000880210588566361,
- ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
- ParamQ = 1349199015905534965792122312016505075413456283393,
- ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669,
-
- Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)],
- ?line Sig1 = my_dss_sign(sized_binary(Msg), Params ++ [crypto:mpint(PrivKey)]),
-
- ?line m(my_dss_verify(sized_binary(Msg), Sig1,
- Params ++ [crypto:mpint(PubKey)]), true),
-
- ?line m(my_dss_verify(sized_binary(one_bit_wrong(Msg)), Sig1,
- Params ++ [crypto:mpint(PubKey)]), false),
-
- ?line m(my_dss_verify(sized_binary(Msg), one_bit_wrong(Sig1),
- Params ++ [crypto:mpint(PubKey)]), false),
+negative_verify(Type, Hash, Msg, Signature, Public) ->
+ case crypto:verify(Type, Hash, Msg, Signature, Public) of
+ true ->
+ ct:fail({{crypto, verify, [Type, Hash, Msg, Signature, Public]}, should_fail});
+ false ->
+ ok
+ end.
- %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]),
+do_public_encrypt({Type, Public, Private, Msg, Padding}) ->
+ PublicEcn = crypto:public_encrypt(Type, Msg, Public, Padding),
+ case crypto:private_decrypt(Type, PublicEcn, Private, Padding) of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}})
+ end.
+do_private_encrypt({Type, Public, Private, Msg, Padding}) ->
+ PrivEcn = crypto:private_encrypt(Type, Msg, Private, Padding),
+ case crypto:public_decrypt(Type, PrivEcn, Public, Padding) of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, Other}})
+ end.
+
+do_generate_compute({srp = Type, UserPrivate, UserGenParams, UserComParams,
+ HostPublic, HostPrivate, HostGenParams, HostComParam, SessionKey}) ->
+ {UserPublic, UserPrivate} = crypto:generate_key(Type, UserGenParams, UserPrivate),
+ {HostPublic, HostPrivate} = crypto:generate_key(Type, HostGenParams, HostPrivate),
+ SessionKey = crypto:compute_key(Type, HostPublic, {UserPublic, UserPrivate},
+ UserComParams),
+ SessionKey = crypto:compute_key(Type, UserPublic, {HostPublic, HostPrivate},
+ HostComParam);
+do_generate_compute({dh, P, G}) ->
+ {UserPub, UserPriv} = crypto:generate_key(dh, [P, G]),
+ {HostPub, HostPriv} = crypto:generate_key(dh, [P, G]),
+ SharedSecret = crypto:compute_key(dh, HostPub, UserPriv, [P, G]),
+ SharedSecret = crypto:compute_key(dh, UserPub, HostPriv, [P, G]).
- ok.
-
-dsa_sign_hash_test(doc) ->
- "dsa_sign_hash testing";
-dsa_sign_hash_test(suite) ->
- [];
-dsa_sign_hash_test(Config) when is_list(Config) ->
- Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
- "09812312908312378623487263487623412039812 huagasd">>,
- SHA = crypto:sha(sized_binary(Msg)),
-
- PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978,
- PrivKey = _X = 441502407453038284293378221372000880210588566361,
- ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
- ParamQ = 1349199015905534965792122312016505075413456283393,
- ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669,
-
- Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)],
- ?line Sig1 = crypto:dss_sign(sha, {digest,SHA}, Params ++ [crypto:mpint(PrivKey)]),
+do_compute({ecdh = Type, Pub, Priv, Curve, SharedSecret}) ->
+ Secret = crypto:bytes_to_integer(crypto:compute_key(Type, Pub, Priv, Curve)),
+ case Secret of
+ SharedSecret ->
+ ok;
+ Other ->
+ ct:fail({{crypto, compute_key, [Type, Pub, Priv, Curve]}, {expected, SharedSecret}, {got, Other}})
+ end.
- ?line m(crypto:dss_verify(none, SHA, sized_binary(Sig1),
- Params ++ [crypto:mpint(PubKey)]), true),
+hexstr2bin(S) ->
+ list_to_binary(hexstr2list(S)).
- ?line m(crypto:dss_verify(sized_binary(one_bit_wrong(Msg)), sized_binary(Sig1),
- Params ++ [crypto:mpint(PubKey)]), false),
+hexstr2list([X,Y|T]) ->
+ [mkint(X)*16 + mkint(Y) | hexstr2list(T)];
+hexstr2list([]) ->
+ [].
+mkint(C) when $0 =< C, C =< $9 ->
+ C - $0;
+mkint(C) when $A =< C, C =< $F ->
+ C - $A + 10;
+mkint(C) when $a =< C, C =< $f ->
+ C - $a + 10.
- ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(one_bit_wrong(Sig1)),
- Params ++ [crypto:mpint(PubKey)]), false),
+is_supported(cipher) ->
+ true;
+is_supported(Group) ->
+ lists:member(Group, lists:append([Algo || {_, Algo} <- crypto:supports()])).
+
+block_iolistify(Blocks) ->
+ lists:map(fun do_block_iolistify/1, Blocks).
+stream_iolistify(Streams) ->
+ lists:map(fun do_stream_iolistify/1, Streams).
+
+do_stream_iolistify({Type, Key, PlainText}) ->
+ {Type, iolistify(Key), iolistify(PlainText)};
+do_stream_iolistify({Type, Key, IV, PlainText}) ->
+ {Type, iolistify(Key), IV, iolistify(PlainText)}.
+
+do_block_iolistify({des_cbc = Type, Key, IV, PlainText}) ->
+ {Type, Key, IV, des_iolistify(PlainText)};
+do_block_iolistify({des3_cbc = Type, Key, IV, PlainText}) ->
+ {Type, Key, IV, des_iolistify(PlainText)};
+do_block_iolistify({des3_cbf = Type, Key, IV, PlainText}) ->
+ {Type, Key, IV, des_iolistify(PlainText)};
+do_block_iolistify({Type, Key, PlainText}) ->
+ {Type, iolistify(Key), iolistify(PlainText)};
+do_block_iolistify({Type, Key, IV, PlainText}) ->
+ {Type, iolistify(Key), IV, iolistify(PlainText)}.
+
+iolistify(<<"Test With Truncation">>)->
+ %% Do not iolistify as it spoils this special case
+ <<"Test With Truncation">>;
+iolistify(Msg)->
+ Length = erlang:byte_size(Msg),
+ Split = Length div 2,
+ List0 = binary_to_list(Msg),
+ case lists:split(Split, List0) of
+ {[Element | List1], List2} ->
+ [[Element], List1, List2];
+ {List1, List2}->
+ [List1, List2]
+ end.
+
+des_iolistify(Msg) ->
+ des_iolist(erlang:byte_size(Msg) div 8, Msg, []).
+
+des_iolist(1, Msg, Acc) ->
+ lists:reverse([Msg | Acc]);
+des_iolist(Split, Msg, Acc) ->
+ <<Part:8/binary, Rest/binary>> = Msg,
+ des_iolist(Split-1, Rest, [Part | Acc]).
+
+%%--------------------------------------------------------------------
+mod_pow_aux_test(_, _, _, 0) ->
+ ok;
+mod_pow_aux_test(B, E, M, N) ->
+ Result = crypto:bytes_to_integer(crypto:mod_pow(B, E, M)),
+ Result = ipow(B, E, M),
+ mod_pow_aux_test(B, E*E+1, M*M+1, N-1).
- %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]),
+%% mod_exp in erlang (copied from jungerl's ssh_math.erl)
+ipow(A, B, M) when M > 0, B >= 0 ->
+ if A == 1 ->
+ 1;
+ true ->
+ ipow(A, B, M, 1)
+ end.
- ok.
+ipow(A, 1, M, Prod) ->
+ (A*Prod) rem M;
+ipow(_A, 0, _M, Prod) ->
+ Prod;
+ipow(A, B, M, Prod) ->
+ B1 = B bsr 1,
+ A1 = (A*A) rem M,
+ if B - B1 == B1 ->
+ ipow(A1, B1, M, Prod);
+ true ->
+ ipow(A1, B1, M, (A*Prod) rem M)
+ end.
+zero_bin(N) when is_integer(N) ->
+ N8 = N * 8,
+ <<0:N8/integer>>;
+zero_bin(B) when is_binary(B) ->
+ zero_bin(size(B)).
+xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) ->
+ L1 = binary_to_list(Bin1),
+ L2 = binary_to_list(Bin2),
+ list_to_binary(xor_bytes(L1, L2));
+xor_bytes(L1, L2) ->
+ xor_bytes(L1, L2, []).
-rsa_encrypt_decrypt(doc) ->
- ["Test rsa_public_encrypt and rsa_private_decrypt functions."];
-rsa_encrypt_decrypt(suite) -> [];
-rsa_encrypt_decrypt(Config) when is_list(Config) ->
- PubEx = 65537,
- PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
- Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
-
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
+xor_bytes([], [], Acc) ->
+ lists:reverse(Acc);
+xor_bytes([N1 | Tl1], [N2 | Tl2], Acc) ->
+ xor_bytes(Tl1, Tl2, [N1 bxor N2 | Acc]).
- Msg = <<"7896345786348 Asldi">>,
+%%--------------------------------------------------------------------
+%% Test data ------------------------------------------------
+%%--------------------------------------------------------------------
+group_config(md4 = Type, Config) ->
+ Msgs = rfc_1321_msgs(),
+ Digests = rfc_1321_md4_digests(),
+ [{hash, {Type, Msgs, Digests}} | Config];
+group_config(md5 = Type, Config) ->
+ Msgs = rfc_1321_msgs(),
+ Digests = rfc_1321_md5_digests(),
+ Keys = rfc_2202_md5_keys(),
+ Data = rfc_2202_msgs(),
+ Hmac = rfc_2202_hmac_md5(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(ripemd160 = Type, Config) ->
+ Msgs = ripemd160_msgs(),
+ Digests = ripemd160_digests(),
+ [{hash, {Type, Msgs, Digests}} | Config];
+group_config(sha = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2_1()],
+ Digests = rfc_4634_sha_digests(),
+ Keys = rfc_2202_sha_keys(),
+ Data = rfc_2202_msgs(),
+ Hmac = rfc_2202_hmac_sha(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(sha224 = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2_1()],
+ Digests = rfc_4634_sha224_digests(),
+ Keys = rfc_4231_keys(),
+ Data = rfc_4231_msgs(),
+ Hmac = rfc4231_hmac_sha224(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(sha256 = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2_1()],
+ Digests = rfc_4634_sha256_digests(),
+ Keys = rfc_4231_keys(),
+ Data = rfc_4231_msgs(),
+ Hmac = rfc4231_hmac_sha256(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(sha384 = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2()],
+ Digests = rfc_4634_sha384_digests(),
+ Keys = rfc_4231_keys(),
+ Data = rfc_4231_msgs(),
+ Hmac = rfc4231_hmac_sha384(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(sha512 = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2()],
+ Digests = rfc_4634_sha512_digests(),
+ Keys = rfc_4231_keys(),
+ Data = rfc_4231_msgs(),
+ Hmac = rfc4231_hmac_sha512(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(rsa = Type, Config) ->
+ Msg = rsa_plain(),
+ Public = rsa_public(),
+ Private = rsa_private(),
+ SignVerify = [{Type, md5, Public, Private, Msg},
+ {Type, sha, Public, Private, Msg},
+ {Type, sha224, Public, Private,Msg},
+ {Type, sha256, Public, Private,Msg}
+ %% {Type, sha384, Public, Private,Msg},
+ %% {Type, sha512, Public, Private, Msg}
+ ],
+ MsgPubEnc = <<"7896345786348 Asldi">>,
+ PubPrivEnc = [{rsa, Public, Private, MsgPubEnc, rsa_pkcs1_padding}
+ %%{rsa, Public, Private, MsgPubEnc, rsa_pkcs1_oaep_padding}
+ %%{rsa, Public, Private, MsgPubEnc, rsa_no_padding}
+ ],
+ [{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
+group_config(dss = Type, Config) ->
+ Msg = dss_plain(),
+ Public = dss_params() ++ [dss_public()],
+ Private = dss_params() ++ [dss_private()],
+ SignVerify = [{Type, sha, Public, Private, Msg}],
+ [{sign_verify, SignVerify} | Config];
+
+group_config(ecdsa = Type, Config) ->
+ {Private, Public} = ec_key_named(),
+ Msg = ec_msg(),
+ SignVerify = [{Type, sha, Public, Private, Msg}],
+ [{sign_verify, SignVerify} | Config];
+group_config(srp, Config) ->
+ GenerateCompute = [srp3(), srp6(), srp6a()],
+ [{generate_compute, GenerateCompute} | Config];
+group_config(ecdh, Config) ->
+ Compute = [ecdh()],
+ [{compute, Compute} | Config];
+group_config(dh, Config) ->
+ GenerateCompute = [dh()],
+ [{generate_compute, GenerateCompute} | Config];
+group_config(des_cbc, Config) ->
+ Block = des_cbc(),
+ [{block, Block} | Config];
+group_config(des_cfb, Config) ->
+ Block = des_cfb(),
+ [{block, Block} | Config];
+group_config(des3_cbc, Config) ->
+ Block = des3_cbc(),
+ [{block, Block} | Config];
+group_config(des3_cbf, Config) ->
+ Block = des3_cbf(),
+ [{block, Block} | Config];
+group_config(rc2_cbc, Config) ->
+ Block = rc2_cbc(),
+ [{block, Block} | Config];
+group_config(aes_cbc128, Config) ->
+ Block = aes_cbc128(),
+ [{block, Block} | Config];
+group_config(aes_cbc256, Config) ->
+ Block = aes_cbc256(),
+ [{block, Block} | Config];
+group_config(aes_cfb128, Config) ->
+ Block = aes_cfb128(),
+ [{block, Block} | Config];
+group_config(blowfish_cbc, Config) ->
+ Block = blowfish_cbc(),
+ [{block, Block} | Config];
+group_config(blowfish_ecb, Config) ->
+ Block = blowfish_ecb(),
+ [{block, Block} | Config];
+group_config(blowfish_cfb64, Config) ->
+ Block = blowfish_cfb64(),
+ [{block, Block} | Config];
+group_config(blowfish_ofb64, Config) ->
+ Block = blowfish_ofb64(),
+ [{block, Block} | Config];
+group_config(rc4, Config) ->
+ Stream = rc4(),
+ [{stream, Stream} | Config];
+group_config(aes_ctr, Config) ->
+ Stream = aes_ctr(),
+ [{stream, Stream} | Config];
+group_config(_, Config) ->
+ Config.
- ?line PKCS1 = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
- ?line PKCS1Dec = crypto:rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
- io:format("PKCS1Dec ~p~n",[PKCS1Dec]),
- ?line Msg = PKCS1Dec,
-
- ?line OAEP = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
- ?line Msg = crypto:rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
-
- <<Msg2Len:32,_/binary>> = crypto:mpint(Mod),
- Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)),
- ?line NoPad = crypto:rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
- ?line NoPadDec = crypto:rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
- ?line NoPadDec = Msg2,
-
- ShouldBeError = (catch crypto:rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
- ?line {'EXIT', {encrypt_failed,_}} = ShouldBeError,
-
-%% ?line SSL = crypto:rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
-%% ?line Msg = crypto:rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
-
- ?line PKCS1_2 = crypto:rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
- ?line PKCS1_2Dec = crypto:rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
- io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]),
- ?line Msg = PKCS1_2Dec,
-
- ?line PKCS1_3 = crypto:rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
- ?line PKCS1_3Dec = crypto:rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
- io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]),
- ?line Msg2 = PKCS1_3Dec,
+rfc_1321_msgs() ->
+ [<<"">>,
+ <<"a">>,
+ <<"abc">>,
+ <<"message digest">>,
+ <<"abcdefghijklmnopqrstuvwxyz">>,
+ <<"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789">>,
+ <<"12345678901234567890123456789012345678901234567890123456789012345678901234567890">>
+ ].
+
+rfc_1321_md4_digests() ->
+ [hexstr2bin("31d6cfe0d16ae931b73c59d7e0c089c0"),
+ hexstr2bin("bde52cb31de33e46245e05fbdbd6fb24"),
+ hexstr2bin("a448017aaf21d8525fc10ae87aa6729d"),
+ hexstr2bin("d9130a8164549fe818874806e1c7014b"),
+ hexstr2bin("d79e1c308aa5bbcdeea8ed63df412da9"),
+ hexstr2bin("043f8582f241db351ce627e153e7f0e4"),
+ hexstr2bin("e33b4ddc9c38f2199c3e7b164fcc0536")].
+
+rfc_1321_md5_digests() ->
+ [hexstr2bin("d41d8cd98f00b204e9800998ecf8427e"),
+ hexstr2bin("0cc175b9c0f1b6a831c399e269772661"),
+ hexstr2bin("900150983cd24fb0d6963f7d28e17f72"),
+ hexstr2bin("f96b697d7cb7938d525a2f31aaf161d0"),
+ hexstr2bin("c3fcd3d76192e4007dfb496cca67e13b"),
+ hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f"),
+ hexstr2bin("57edf4a22be3c955ac49da2e2107b67a")].
+
+rfc_4634_test1() ->
+ <<"abc">>.
+rfc_4634_test2_1() ->
+ <<"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq">>.
+rfc_4634_test2_2a() ->
+ <<"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn">>.
+rfc_4634_test2_2b() ->
+ <<"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu">>.
+rfc_4634_test2() ->
+ A2 =rfc_4634_test2_2a(),
+ B2 = rfc_4634_test2_2b(),
+ <<A2/binary, B2/binary>>.
+
+rfc_4634_sha_digests()->
+ [hexstr2bin("A9993E364706816ABA3E25717850C26C9CD0D89D"),
+ hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")].
+rfc_4634_sha224_digests() ->
+ [hexstr2bin("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"),
+ hexstr2bin("75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B1952522525")].
+rfc_4634_sha256_digests() ->
+ [
+ hexstr2bin("BA7816BF8F01CFEA4141"
+ "40DE5DAE2223B00361A396177A9CB410FF61F20015AD"),
+ hexstr2bin("248D6A61D20638B8"
+ "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")
+ ].
+rfc_4634_sha384_digests() ->
+ [hexstr2bin("CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7"),
+ hexstr2bin("09330C33F71147E83D192FC782CD1B4753111B173B3B05D22FA08086E3B0F712FCC7C71A557E2DB966C3E9FA91746039")
+ ].
+rfc_4634_sha512_digests() ->
+ [hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
+ "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
+ "454D4423643CE80E2A9AC94FA54CA49F"),
+ hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA17299AEADB6889018501D289E4900F7E4331B99DEC4B5433AC7D329EEB6DD26545E96E55B874BE909")].
+
+ripemd160_msgs() ->
+ [<<"">>,
+ <<"a">>,
+ <<"abc">>,
+ <<"message digest">>,
+ <<"abcdefghijklmnopqrstuvwxyz">>,
+ <<"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq">>,
+ <<"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789">>
+ ].
+
+ripemd160_digests() ->
+ [hexstr2bin("9c1185a5c5e9fc54612808977ee8f548b2258d31"),
+ hexstr2bin("0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"),
+ hexstr2bin("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"),
+ hexstr2bin("5d0689ef49d2fae572b881b123a85ffa21595f36"),
+ hexstr2bin("f71c27109c692c1b56bbdceb5b9d2865b3708dbc"),
+ hexstr2bin("12a053384a9c0c88e405a06c27dcf49ada62eb2b"),
+ hexstr2bin("b0e20b6e3116640286ed3a87a5713079b21f5189")
+ ].
+
+ripemd160_incr_msgs() ->
+ [<<"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg">>,<<"hijklmnopqrstuvwxyz0123456789">>].
+ripemd160_incr_digest() ->
+ hexstr2bin("b0e20b6e3116640286ed3a87a5713079b21f5189").
+
+rfc_2202_md5_keys() ->
+ [binary:copy(<<16#0b>>, 16),
+ <<"Jefe">>,
+ binary:copy(<<16#aa>>, 16),
+ list_to_binary(lists:seq(1, 16#19)),
+ binary:copy(<<16#0c>>, 16),
+ binary:copy(<<16#aa>>, 80),
+ binary:copy(<<16#aa>>, 80)].
+
+rfc_2202_sha_keys() ->
+ [binary:copy(<<16#0b>>, 20),
+ <<"Jefe">>,
+ binary:copy(<<16#aa>>, 20),
+ list_to_binary(lists:seq(1, 16#19)),
+ binary:copy(<<16#0c>>, 20),
+ binary:copy(<<16#aa>>, 80),
+ binary:copy(<<16#aa>>, 80)].
+
+rfc_2202_msgs()->
+ [<<"Hi There">>,
+ <<"what do ya want for nothing?">>,
+ binary:copy(<<16#dd>>, 50),
+ binary:copy(<<16#cd>>, 50),
+ <<"Test With Truncation">>,
+ <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>
+ ].
+
+hmac_key(md5) ->
+ [<<"A fine speach">>, <<"by a fine man!">>];
+hmac_key(_) ->
+ hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f").
+hmac_inc(_) ->
+ [<<"Sampl">>, <<"e #1">>].
+
+rfc_2202_hmac_md5() ->
+ [
+ hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d"),
+ hexstr2bin("750c783e6ab0b503eaa86e310a5db738"),
+ hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6"),
+ hexstr2bin("697eaf0aca3a3aea3a75164746ffaa79"),
+ hexstr2bin("56461ef2342edc00f9bab995690efd4c"),
+ hexstr2bin("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"),
+ hexstr2bin("6f630fad67cda0ee1fb1f562db3aa53e")
+ ].
+
+rfc_2202_hmac_sha() ->
+ [
+ hexstr2bin("b617318655057264e28bc0b6fb378c8ef146be00"),
+ hexstr2bin("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"),
+ hexstr2bin("125d7342b9ac11cd91a39af48aa17b4f63f175d3"),
+ hexstr2bin("4c9007f4026250c6bc8414f9bf50c86c2d7235da"),
+ hexstr2bin("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
+ hexstr2bin("aa4ae5e15272d00e95705637ce8a3b55ed402112"),
+ hexstr2bin("e8e99d0f45237d786d6bbaa7965c7808bbff1a91")
+ ].
+
+
+rfc_4231_keys() ->
+ [binary:copy(<<16#0b>>, 20),
+ <<"Jefe">>,
+ binary:copy(<<16#aa>>, 20),
+ list_to_binary(lists:seq(1, 16#19)),
+ binary:copy(<<16#0c>>, 20),
+ binary:copy(<<16#aa>>, 131),
+ binary:copy(<<16#aa>>, 131)
+ ].
- ?line {'EXIT', {encrypt_failed,_}} =
- (catch crypto:rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
+rfc_4231_msgs() ->
+ [<<"Hi There">>,
+ <<"what do ya want for nothing?">>,
+ binary:copy(<<16#dd>>, 50),
+ binary:copy(<<16#cd>>, 50),
+ <<"Test With Truncation">>,
+ <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ <<"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.">>
+ ].
- ok.
-
-
-dh(doc) ->
- ["Test dh (Diffie-Hellman) functions."];
-dh(suite) -> [];
-dh(Config) when is_list(Config) ->
- Self = self(),
- GenP = fun() ->
- %% Gen Param may take arbitrary long time to finish
- %% That's not a bug in erlang crypto application.
- ?line DHPs = crypto:dh_generate_parameters(512,2),
- ?line ok = crypto:dh_check(DHPs),
- Self ! {param, DHPs}
- end,
- Pid = spawn(GenP),
- receive
- {param, DHPs} ->
- timer:sleep(100),
- io:format("DHP ~p~n", [DHPs]),
- ?line {Pub1,Priv1} = crypto:dh_generate_key(DHPs),
- io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]),
- ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs),
- io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]),
- ?line A = crypto:dh_compute_key(Pub1, Priv2, DHPs),
- timer:sleep(100), %% Get another thread see if that triggers problem
- ?line B = crypto:dh_compute_key(Pub2, Priv1, DHPs),
- io:format("A ~p~n",[A]),
- io:format("B ~p~n",[B]),
- ?line A = B
- after 50000 ->
- io:format("Killing Param generation which took to long ~p~n",[Pid]),
- 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) ->
+rfc4231_hmac_sha224() ->
+ [hexstr2bin("896fb1128abbdf196832107cd49df33f"
+ "47b4b1169912ba4f53684b22"),
+ hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
+ "8bbea2a39e6148008fd05e44"),
+ hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
+ "9365b0c1f65d69d1ec8333ea"),
+ hexstr2bin("6c11506874013cac6a2abc1bb382627c"
+ "ec6a90d86efc012de7afec5a"),
+ hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
+ hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
+ "d499f112f2d2b7273fa6870e"),
+ hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
+ "946770db9c2b95c9f6f565d1")].
+rfc4231_hmac_sha256() ->
+ [hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
+ "881dc200c9833da726e9376c2e32cff7"),
+ hexstr2bin("5bdcc146bf60754e6a042426089575c7"
+ "5a003f089d2739839dec58b964ec3843"),
+ hexstr2bin("773ea91e36800e46854db8ebd09181a7"
+ "2959098b3ef8c122d9635514ced565fe"),
+ hexstr2bin("82558a389a443c0ea4cc819899f2083a"
+ "85f0faa3e578f8077a2e3ff46729665b"),
+ hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
+ hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
+ "8e0bc6213728c5140546040f0ee37f54"),
+ hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
+ "bfdc63644f0713938a7f51535c3a35e2")].
+
+rfc4231_hmac_sha384() ->
+ [hexstr2bin("afd03944d84895626b0825f4ab46907f"
+ "15f9dadbe4101ec682aa034c7cebc59c"
+ "faea9ea9076ede7f4af152e8b2fa9cb6"),
+ hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
+ "9c7ef464f5a01b47e42ec3736322445e"
+ "8e2240ca5e69e2c78b3239ecfab21649"),
+ hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
+ "0aa635d947ac9febe83ef4e55966144b"
+ "2a5ab39dc13814b94e3ab6e101a34f27"),
+ hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
+ "7a9981480850009cc5577c6e1f573b4e"
+ "6801dd23c4a7d679ccf8a386c674cffb"),
+ hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
+ hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
+ "4f9ef1012a2b588f3cd11f05033ac4c6"
+ "0c2ef6ab4030fe8296248df163f44952"),
+ hexstr2bin("6617178e941f020d351e2f254e8fd32c"
+ "602420feb0b8fb9adccebb82461e99c5"
+ "a678cc31e799176d3860e6110c46523e")].
+rfc4231_hmac_sha512() ->
+ [hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
+ "2379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4"
+ "be9d914eeb61f1702e696c203a126854"),
+ hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
+ "87bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fd"
+ "caeab1a34d4a6b4b636e070a38bce737"),
+ hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
+ "b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807"
+ "b946a337bee8942674278859e13292fb"),
+ hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
+ "e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063"
+ "a5f19741120c4f2de2adebeb10a298dd"),
+ hexstr2bin("415fad6271580a531d4179bc891d87a6"),
+ hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
+ "9b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e52"
+ "95e64f73f63f0aec8b915a985d786598"),
+ hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
+ "debd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15"
+ "134676fb6de0446065c97440fa8c6a58")].
+des_cbc() ->
+ [{des_cbc,
+ hexstr2bin("0123456789abcdef"),
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">> }].
+
+des_cfb() ->
+ [{des_cfb,
+ hexstr2bin("0123456789abcdef"),
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the">>}].
+
+des3_cbc() ->
+ [{des3_cbc,
+ [hexstr2bin("0123456789abcdef"),
+ hexstr2bin("fedcba9876543210"),
+ hexstr2bin("0f2d4b6987a5c3e1")],
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">>
+ }].
+
+des3_cbf() ->
+ [{des3_cbf,
+ [hexstr2bin("0123456789abcdef"),
+ hexstr2bin("fedcba9876543210"),
+ hexstr2bin("0f2d4b6987a5c3e1")],
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">>
+ }].
+
+rc2_cbc() ->
+ [{rc2_cbc,
+ <<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
+ <<72,91,135,182,25,42,35,210>>,
+ <<36,245,206,158,168,230,58,69,148,137,32,192,250,41,237,181,181,251, 192,2,175,135,177,171,57,30,111,117,159,149,15,28,88,158,28,81,28,115, 85,219,241,82,117,222,91,85,73,117,164,25,182,52,191,64,123,57,26,19, 211,27,253,31,194,219,231,104,247,240,172,130,119,21,225,154,101,247, 32,216,42,216,133,169,78,22,97,27,227,26,196,224,172,168,17,9,148,55, 203,91,252,40,61,226,236,221,215,160,78,63,13,181,68,57,196,241,185, 207, 116,129,152,237,60,139,247,153,27,146,161,246,222,98,185,222,152, 187,135, 236,86,34,7,110,91,230,173,34,160,242,202,222,121,127,181,140, 101,203,195, 190,88,250,86,147,127,87,72,126,171,16,71,47,110,248,88, 14,29,143,161,152, 129,236,148,22,152,186,208,119,70,8,174,193,203,100, 193,203,200,117,102,242, 134,142,96,125,135,200,217,190,76,117,50,70, 209,186,101,241,200,91,40,193,54, 90,195,38,47,59,197,38,234,86,223,16, 51,253,204,129,20,171,66,21,241,26,135,216, 196,114,110,91,15,53,40, 164,201,136,113,95,247,51,181,208,241,68,168,98,151,36, 155,72,24,57, 42,191,14,125,204,10,167,214,233,138,115,125,234,121,134,227,26,247, 77,200,117,110,117,111,168,156,206,67,159,149,189,173,150,193,91,199, 216,153,22, 189,137,185,89,160,13,131,132,58,109,28,110,246,252,251,14, 232,91,38,52,29,101,188,69,123,50,0,130,178,93,73,239,118,7,77,35,59, 253,10,159,45,86,142,37,78,232,48>>
+ }].
+aes_cbc128() ->
+ [{aes_cbc128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("000102030405060708090a0b0c0d0e0f"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_cbc128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("7649ABAC8119B246CEE98E9B12E9197D"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_cbc128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("5086CB9B507219EE95DB113A917678B2"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_cbc128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("73BED6B8E3C1743B7116E69E22229516"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+aes_cbc256() ->
+ [{aes_cbc256,
+ hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("000102030405060708090A0B0C0D0E0F"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_cbc256,
+ hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("F58C4C04D6E5F1BA779EABFB5F7BFBD6"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_cbc256,
+ hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("9CFC4E967EDB808D679F777BC6702C7D"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_cbc256,
+ hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("39F23369A9D9BACFA530E26304231461"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+aes_cfb128() ->
+ [{aes_cfb128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("000102030405060708090a0b0c0d0e0f"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_cfb128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("3B3FD92EB72DAD20333449F8E83CFB4A"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_cfb128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("C8A64537A0B3A93FCDE3CDAD9F1CE58B"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_cfb128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("26751F67A3CBB140B1808CF187A4F4DF"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+blowfish_cbc() ->
+ [{blowfish_cbc,
+ hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000000000")
+ }].
+
+blowfish_ecb() ->
+ [
+ {blowfish_ecb,
+ hexstr2bin("0000000000000000"),
+ hexstr2bin("0000000000000000")},
+ {blowfish_ecb,
+ hexstr2bin("FFFFFFFFFFFFFFFF"),
+ hexstr2bin("FFFFFFFFFFFFFFFF")},
+ {blowfish_ecb,
+ hexstr2bin("3000000000000000"),
+ hexstr2bin("1000000000000001")},
+ {blowfish_ecb,
+ hexstr2bin("1111111111111111"),
+ hexstr2bin("1111111111111111")},
+ {blowfish_ecb,
+ hexstr2bin("0123456789ABCDEF"),
+ hexstr2bin("1111111111111111")},
+ {blowfish_ecb,
+ hexstr2bin("0000000000000000"),
+ hexstr2bin("0000000000000000")},
+ {blowfish_ecb,
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("0123456789ABCDEF")},
+ {blowfish_ecb,
+ hexstr2bin("7CA110454A1A6E57"),
+ hexstr2bin("01A1D6D039776742")},
+ {blowfish_ecb,
+ hexstr2bin("0131D9619DC1376E"),
+ hexstr2bin("5CD54CA83DEF57DA")},
+ {blowfish_ecb,
+ hexstr2bin("07A1133E4A0B2686"),
+ hexstr2bin("0248D43806F67172")},
+ {blowfish_ecb,
+ hexstr2bin("3849674C2602319E"),
+ hexstr2bin("51454B582DDF440A")},
+ {blowfish_ecb,
+ hexstr2bin("04B915BA43FEB5B6"),
+ hexstr2bin("42FD443059577FA2")},
+ {blowfish_ecb,
+ hexstr2bin("0113B970FD34F2CE"),
+ hexstr2bin("059B5E0851CF143A")},
+ {blowfish_ecb,
+ hexstr2bin("0170F175468FB5E6"),
+ hexstr2bin("0756D8E0774761D2")},
+ {blowfish_ecb,
+ hexstr2bin("43297FAD38E373FE"),
+ hexstr2bin("762514B829BF486A")},
+ {blowfish_ecb,
+ hexstr2bin("07A7137045DA2A16"),
+ hexstr2bin("3BDD119049372802")},
+ {blowfish_ecb,
+ hexstr2bin("04689104C2FD3B2F"),
+ hexstr2bin("26955F6835AF609A")},
+ {blowfish_ecb,
+ hexstr2bin("37D06BB516CB7546"),
+ hexstr2bin("164D5E404F275232")},
+ {blowfish_ecb,
+ hexstr2bin("1F08260D1AC2465E"),
+ hexstr2bin("6B056E18759F5CCA")},
+ {blowfish_ecb,
+ hexstr2bin("584023641ABA6176"),
+ hexstr2bin("004BD6EF09176062")},
+ {blowfish_ecb,
+ hexstr2bin("025816164629B007"),
+ hexstr2bin("480D39006EE762F2")},
+ {blowfish_ecb,
+ hexstr2bin("49793EBC79B3258F"),
+ hexstr2bin("437540C8698F3CFA")},
+ {blowfish_ecb,
+ hexstr2bin("018310DC409B26D6"),
+ hexstr2bin("1D9D5C5018F728C2")},
+ {blowfish_ecb,
+ hexstr2bin("1C587F1C13924FEF"),
+ hexstr2bin("305532286D6F295A")},
+ {blowfish_ecb,
+ hexstr2bin("0101010101010101"),
+ hexstr2bin("0123456789ABCDEF")},
+ {blowfish_ecb,
+ hexstr2bin("1F1F1F1F0E0E0E0E"),
+ hexstr2bin("0123456789ABCDEF")},
+ {blowfish_ecb,
+ hexstr2bin("E0FEE0FEF1FEF1FE"),
+ hexstr2bin("0123456789ABCDEF")},
+ {blowfish_ecb,
+ hexstr2bin("0000000000000000"),
+ hexstr2bin("FFFFFFFFFFFFFFFF")},
+ {blowfish_ecb,
+ hexstr2bin("FFFFFFFFFFFFFFFF"),
+ hexstr2bin("0000000000000000")},
+ {blowfish_ecb,
+ hexstr2bin("0123456789ABCDEF"),
+ hexstr2bin("0000000000000000")},
+ {blowfish_ecb,
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("FFFFFFFFFFFFFFFF")}
+ ].
+
+blowfish_cfb64() ->
+ [{blowfish_cfb64,
+ hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000")
+ }].
+blowfish_ofb64() ->
+ [{blowfish_ofb64,
+ hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000")
+ }].
+
+rc4() ->
+ [{rc4, <<"apaapa">>, <<"Yo baby yo">>},
+ {rc4, <<"apaapa">>, list_to_binary(lists:seq(0, 255))}
+ ].
+
+aes_ctr() ->
+ [ %% F.5.3 CTR-AES192.Encrypt
+ {aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef") },
+ {aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")},
+
+ %% F.5.3 CTR-AES192.Encrypt
+ {aes_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")},
+
+ %% F.5.5 CTR-AES256.Encrypt
+ {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+rsa_plain() ->
+ <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>.
+rsa_public() ->
+ [65537, 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123].
+rsa_private() ->
+ rsa_public() ++ [7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945].
+
+dss_plain() ->
+ rsa_plain().
+dss_public() ->
+ 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978.
+dss_private() ->
+ 441502407453038284293378221372000880210588566361.
+dss_params() ->
+ [109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
+ 1349199015905534965792122312016505075413456283393,
+ 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669].
+
+ec_key_named() ->
+ {D2_pub, D2_priv} = crypto:generate_key(ecdh, sect113r2),
+ {[D2_priv, sect113r2], [D2_pub, sect113r2]}.
+
+ec_msg() ->
+ <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>.
+
+srp3() ->
Username = <<"alice">>,
Password = <<"password123">>,
Salt = hexstr2bin("2857827A19266A1F2BC6"),
@@ -1889,21 +1253,12 @@ srp3(Config) when is_list(Config) ->
"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) ->
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+ srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPrivate, UserPassHash, Scrambler, SessionKey).
+
+srp6() ->
Username = <<"alice">>,
Password = <<"password123">>,
Salt = hexstr2bin("2857827A19266A1F2BC6"),
@@ -1940,21 +1295,12 @@ srp6(Config) when is_list(Config) ->
"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) ->
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+ srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPrivate, UserPassHash, Scrambler, SessionKey).
+
+srp6a() ->
Username = <<"alice">>,
Password = <<"password123">>,
Salt = hexstr2bin("BEB25379D1A8581EB5A727673A2441EE"),
@@ -1976,275 +1322,36 @@ srp6a(Config) when is_list(Config) ->
ServerPrivate = hexstr2bin("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D1"
"05284D20"),
ClientPublic = hexstr2bin("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4"
- "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
- "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
- "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
- "B349EF5D76988A3672FAC47B0769447B"),
+ "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
+ "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
+ "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
+ "B349EF5D76988A3672FAC47B0769447B"),
ServerPublic = hexstr2bin("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011"
- "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99"
- "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA"
- "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE"
- "EB4012B7D7665238A8E3FB004B117B58"),
-
+ "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) ->
- ["Test the exor function."];
-exor_test(suite) ->
- [];
-exor_test(Config) when is_list(Config) ->
- B = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>,
- Z1 = zero_bin(B),
- Z1 = crypto:exor(B, B),
- B1 = crypto:rand_bytes(100),
- B2 = crypto:rand_bytes(100),
- Z2 = zero_bin(B1),
- Z2 = crypto:exor(B1, B1),
- Z2 = crypto:exor(B2, B2),
- R = xor_bytes(B1, B2),
- R = crypto:exor(B1, B2),
- ok.
-
-%%
-%%
-rc4_test(doc) ->
- ["Test rc4 encryption ."];
-rc4_test(suite) ->
- [];
-rc4_test(Config) when is_list(Config) ->
- CT1 = <<"Yo baby yo">>,
- R1 = <<118,122,68,110,157,166,141,212,139,39>>,
- K = "apaapa",
- R1 = crypto:rc4_encrypt(K, CT1),
- CT1 = crypto:rc4_encrypt(K, R1),
- CT2 = lists:seq(0, 255),
- R2 = crypto:rc4_encrypt(K, CT2),
- CT2 = binary_to_list(crypto:rc4_encrypt(K, R2)),
- ok.
-
-rc4_stream_test(doc) ->
- ["Test rc4 stream encryption ."];
-rc4_stream_test(suite) ->
- [];
-rc4_stream_test(Config) when is_list(Config) ->
- CT1 = <<"Yo ">>,
- CT2 = <<"baby yo">>,
- K = "apaapa",
- State0 = crypto:rc4_set_key(K),
- {State1, R1} = crypto:rc4_encrypt_with_state(State0, CT1),
- {_State2, R2} = crypto:rc4_encrypt_with_state(State1, CT2),
- R = list_to_binary([R1, R2]),
- <<118,122,68,110,157,166,141,212,139,39>> = R,
- ok.
-
-blowfish_cfb64(doc) -> ["Test Blowfish encrypt/decrypt."];
-blowfish_cfb64(suite) -> [];
-blowfish_cfb64(Config) when is_list(Config) ->
- Key = <<1,35,69,103,137,171,205,239,240,225,210,195,180,165,150,135>>,
-
- IVec = <<254,220,186,152,118,84,50,16>>,
- Plain = <<"7654321 Now is the time for ">>,
- Enc = <<231,50,20,162,130,33,57,202,242,110,207,109,46,185,231,110,61,163,222,4,209,81,114,0,81,157,87,166>>,
-
- Enc = crypto:blowfish_cfb64_encrypt(Key, IVec, Plain),
- Plain = crypto:blowfish_cfb64_decrypt(Key, IVec, Enc),
-
- Key2 = <<"A2B4C">>,
- IVec2 = <<"12345678">>,
- Plain2 = <<"badger at my table....!">>,
- Enc2 = <<173,76,128,155,70,81,79,228,4,162,188,92,119,53,144,89,93,236,28,164,176,16,138>>,
-
- Enc2 = crypto:blowfish_cfb64_encrypt(Key2, IVec2, Plain2),
- Plain2 = crypto:blowfish_cfb64_decrypt(Key2, IVec2, Enc2).
-
-
-smp(doc) -> "Check concurrent access to crypto driver";
-smp(suite) -> [];
-smp(Config) ->
- case erlang:system_info(smp_support) of
- true ->
- NumOfProcs = erlang:system_info(schedulers),
- io:format("smp starting ~p workers\n",[NumOfProcs]),
- Seeds = [random:uniform(9999) || _ <- lists:seq(1,NumOfProcs)],
- Parent = self(),
- Pids = [spawn_link(fun()-> worker(Seed,Config,Parent) end)
- || Seed <- Seeds],
- wait_pids(Pids);
-
- false ->
- {skipped,"No smp support"}
- end.
-
-worker(Seed, Config, Parent) ->
- io:format("smp worker ~p, seed=~p~n",[self(),Seed]),
- random:seed(Seed,Seed,Seed),
- worker_loop(100, Config),
- %%io:format("worker ~p done\n",[self()]),
- Parent ! self().
-
-worker_loop(0, _) ->
- ok;
-worker_loop(N, Config) ->
- Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc,
- 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_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]),
- ?MODULE:F(Config),
- worker_loop(N-1,Config).
-
-wait_pids([]) ->
- ok;
-wait_pids(Pids) ->
- receive
- Pid ->
- ?line true = lists:member(Pid,Pids),
- Others = lists:delete(Pid,Pids),
- io:format("wait_pid got ~p, still waiting for ~p\n",[Pid,Others]),
- wait_pids(Others)
- end.
-
-%%
-%% Help functions
-%%
-
-% match
-m(X, X) ->
- ?line true.
-t(true) ->
- true.
-
-% hexstr2bin
-hexstr2bin(S) ->
- list_to_binary(hexstr2list(S)).
-
-hexstr2list([X,Y|T]) ->
- [mkint(X)*16 + mkint(Y) | hexstr2list(T)];
-hexstr2list([]) ->
- [].
-
-mkint(C) when $0 =< C, C =< $9 ->
- C - $0;
-mkint(C) when $A =< C, C =< $F ->
- C - $A + 10;
-mkint(C) when $a =< C, C =< $f ->
- C - $a + 10.
-
-%% mod_exp in erlang (copied from jungerl's ssh_math.erl)
-ipow(A, B, M) when M > 0, B >= 0 ->
- if A == 1 ->
- 1;
- true ->
- ipow(A, B, M, 1)
- end.
-
-ipow(A, 1, M, Prod) ->
- (A*Prod) rem M;
-ipow(_A, 0, _M, Prod) ->
- Prod;
-ipow(A, B, M, Prod) ->
- B1 = B bsr 1,
- A1 = (A*A) rem M,
- if B - B1 == B1 ->
- ipow(A1, B1, M, Prod);
- true ->
- ipow(A1, B1, M, (A*Prod) rem M)
- end.
-
-%%
-%% Invert an element X mod P
-%% Calculated as {1, {A,B}} = egcd(X,P),
-%% 1 == P*A + X*B == X*B (mod P) i.e B is the inverse element
-%%
-%% X > 0, P > 0, X < P (P should be prime)
-%%
-%% invert(X,P) when X > 0, P > 0, X < P ->
-%% I = inv(X,P,1,0),
-%% if
-%% I < 0 -> P + I;
-%% true -> I
-%% end.
-
-%% inv(0,_,_,Q) -> Q;
-%% inv(X,P,R1,Q1) ->
-%% D = P div X,
-%% inv(P rem X, X, Q1 - D*R1, R1).
-
-sized_binary(Binary) when is_binary(Binary) ->
- <<(size(Binary)):32/integer, Binary/binary>>;
-sized_binary(List) ->
- sized_binary(list_to_binary(List)).
-
-xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) ->
- L1 = binary_to_list(Bin1),
- L2 = binary_to_list(Bin2),
- list_to_binary(xor_bytes(L1, L2));
-xor_bytes(L1, L2) ->
- xor_bytes(L1, L2, []).
-
-xor_bytes([], [], Acc) ->
- lists:reverse(Acc);
-xor_bytes([N1 | Tl1], [N2 | Tl2], Acc) ->
- xor_bytes(Tl1, Tl2, [N1 bxor N2 | Acc]).
-
-zero_bin(N) when is_integer(N) ->
- N8 = N * 8,
- <<0:N8/integer>>;
-zero_bin(B) when is_binary(B) ->
- zero_bin(size(B)).
-
-my_dss_verify(Data,[Sign|Tail],Key) ->
- Res = my_dss_verify(Data,sized_binary(Sign),Key),
- case Tail of
- [] -> Res;
- _ -> ?line Res = my_dss_verify(Data,Tail,Key)
- end;
-my_dss_verify(Data,Sign,Key) ->
- ?line Res = crypto:dss_verify(Data, Sign, Key),
- ?line Res = crypto:dss_verify(sha, Data, Sign, Key),
- ?line <<_:32,Raw/binary>> = Data,
- ?line Res = crypto:dss_verify(none, crypto:sha(Raw), Sign, Key),
- Res.
-
-my_dss_sign(Data,Key) ->
- ?line S1 = crypto:dss_sign(Data, Key),
- ?line S2 = crypto:dss_sign(sha, Data, Key),
- ?line <<_:32,Raw/binary>> = Data,
- ?line S3 = crypto:dss_sign(none, crypto:sha(Raw), Key),
- [S1,S2,S3].
-
-openssl_version() ->
- case crypto:info_lib() of
- [{<<"OpenSSL">>,LibVer,_}] when is_integer(LibVer) ->
- LibVer;
- _ ->
- undefined
- end.
-
-if_supported(Algorithm, Fun) ->
- case proplists:get_bool(Algorithm, crypto:algorithms()) of
- true ->
- Fun();
- _ ->
- {skipped, io:format("~s not spupported", [Algorithm])}
- end.
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+ srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPrivate, UserPassHash, Scrambler, SessionKey).
+
+srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPrivate, UserPassHash, Scrambler, SessionKey)->
+ {srp, ClientPrivate,
+ {user, [Generator, Prime, Version]}, {user, [UserPassHash, Prime, Generator, Version, Scrambler]},
+ ServerPublic, ServerPrivate, {host, [Verifier, Generator, Prime, Version]},
+ {host, [Verifier, Prime, Version, Scrambler]},
+ SessionKey}.
+ecdh() ->
+ {ecdh, 10053111454769593468622878414300213417816614162107065345116848162553478019161427871683337786549966,
+ 1373339791687564785573162818422814591820885704654,
+ secp160r1, 990333295438215762119481641129490894973766052278}.
+
+dh() ->
+ {dh, 0087761979513264537414556992123116644042638206717762626089877284926656954974893442000747478454809111207351620687968672207938731607963470779396984752680274820156266685080223616226905101126463253150237669547023934604953898814222890239130021414026118792251620881355456432549881723310342870016961804255746630219, 2}.
diff --git a/lib/crypto/test/old_crypto_SUITE.erl b/lib/crypto/test/old_crypto_SUITE.erl
new file mode 100644
index 0000000000..040edbf092
--- /dev/null
+++ b/lib/crypto/test/old_crypto_SUITE.erl
@@ -0,0 +1,2342 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+-module(old_crypto_SUITE).
+
+-include_lib("test_server/include/test_server.hrl").
+
+-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2,
+ init_per_testcase/2,
+ end_per_testcase/2,
+ info/1,
+ link_test/1,
+ md5/1,
+ md5_update/1,
+ md4/1,
+ md4_update/1,
+ sha/1,
+ sha_update/1,
+ hmac_update_sha/1,
+ hmac_update_sha_n/1,
+ hmac_update_sha256/1,
+ hmac_update_sha512/1,
+ hmac_update_md5/1,
+ hmac_update_md5_io/1,
+ hmac_update_md5_n/1,
+ hmac_rfc2202/1,
+ hmac_rfc4231_sha224/1,
+ hmac_rfc4231_sha256/1,
+ hmac_rfc4231_sha384/1,
+ hmac_rfc4231_sha512/1,
+ ripemd160/1,
+ ripemd160_update/1,
+ sha256/1,
+ sha256_update/1,
+ sha512/1,
+ sha512_update/1,
+ md5_mac/1,
+ md5_mac_io/1,
+ des_cbc/1,
+ des_cbc_iter/1,
+ des_cfb/1,
+ des_cfb_iter/1,
+ des_ecb/1,
+ des3_cbc/1,
+ des3_cfb/1,
+ rc2_cbc/1,
+ aes_cfb/1,
+ aes_cbc/1,
+ aes_cbc_iter/1,
+ aes_ctr/1,
+ aes_ctr_stream/1,
+ mod_exp_test/1,
+ rand_uniform_test/1,
+ strong_rand_test/1,
+ rsa_verify_test/1,
+ dsa_verify_test/1,
+ rsa_sign_test/1,
+ rsa_sign_hash_test/1,
+ dsa_sign_test/1,
+ dsa_sign_hash_test/1,
+ rsa_encrypt_decrypt/1,
+ dh/1,
+ srp3/1, srp6/1, srp6a/1,
+ ec/1,
+ exor_test/1,
+ rc4_test/1,
+ rc4_stream_test/1,
+ blowfish_cfb64/1,
+ smp/1]).
+
+-export([hexstr2bin/1]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [link_test, {group, info}].
+
+groups() ->
+ [{info, [sequence],[info, {group, rest}]},
+ {rest, [],
+ [md5, md5_update, md4, md4_update, md5_mac,
+ md5_mac_io, ripemd160, ripemd160_update, sha, sha_update,
+ 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_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, srp3, srp6, srp6a, ec, exor_test,
+ rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
+ smp]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(info, Config) ->
+ Config;
+init_per_testcase(_Name,Config) ->
+ io:format("init_per_testcase\n"),
+ ?line crypto:start(),
+ Config.
+
+end_per_testcase(info, Config) ->
+ Config;
+end_per_testcase(_Name,Config) ->
+ io:format("end_per_testcase\n"),
+ ?line crypto:stop(),
+ Config.
+
+%%
+%%
+link_test(doc) ->
+ ["Test that the library is statically linked to libcrypto.a."];
+link_test(suite) ->
+ [];
+link_test(Config) when is_list(Config) ->
+ ?line case os:type() of
+ {unix,darwin} -> {skipped,"Darwin cannot link statically"};
+ {unix,_} -> link_test_1();
+ _ -> {skip,"Only runs on Unix"}
+ end.
+
+link_test_1() ->
+ ?line CryptoPriv = code:priv_dir(crypto),
+ ?line Wc = filename:join([CryptoPriv,"lib","crypto.*"]),
+ ?line case filelib:wildcard(Wc) of
+ [] -> {skip,"Didn't find the crypto driver"};
+ [Drv] -> link_test_2(Drv)
+ end.
+
+link_test_2(Drv) ->
+ case ldd_program() of
+ none ->
+ {skip,"No ldd-like program found"};
+ Ldd ->
+ Cmd = Ldd ++ " " ++ Drv,
+ Libs = os:cmd(Cmd),
+ io:format("~p\n", [Libs]),
+ case string:str(Libs, "libcrypto") of
+ 0 ->
+ case ?t:is_commercial() of
+ true ->
+ ?t:fail({libcrypto,statically_linked});
+ false ->
+ {comment,"Statically linked (OK for open-source platform)"}
+ end;
+ _ ->
+ ok
+ end
+ end.
+
+ldd_program() ->
+ case os:find_executable("ldd") of
+ false ->
+ case os:type() of
+ {unix,darwin} ->
+ case os:find_executable("otool") of
+ false -> none;
+ Otool -> Otool ++ " -L"
+ end
+ end;
+ Ldd when is_list(Ldd) -> Ldd
+ end.
+
+
+
+info(doc) ->
+ ["Call the info function."];
+info(suite) ->
+ [];
+info(Config) when is_list(Config) ->
+ case {code:lib_dir(crypto),?t:is_commercial()} of
+ {{error,bad_name},false} ->
+ {skip,"Missing crypto application"};
+ {_,_} ->
+ ?line crypto:start(),
+ ?line Info = crypto:info(),
+ ?line Exports = lists:usort([F || {F,_} <- crypto:module_info(exports)]),
+ ?line [] = Info -- Exports,
+ ?line NotInInfo = Exports -- Info,
+ io:format("NotInInfo = ~p\n", [NotInInfo]),
+ %% BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
+ %% dh_check, dh_generate_parameters,
+ %% module_info, start, stop, version]),
+ %% ?line BlackList = NotInInfo,
+
+ ?line InfoLib = crypto:info_lib(),
+ ?line [_|_] = InfoLib,
+ F = fun([{Name,VerN,VerS}|T],Me) ->
+ ?line true = is_binary(Name),
+ ?line true = is_integer(VerN),
+ ?line true = is_binary(VerS),
+ Me(T,Me);
+ ([],_) ->
+ ok
+ end,
+ ?line F(InfoLib,F),
+ ?line crypto:stop()
+ end.
+
+%%
+%%
+md5(doc) ->
+ ["Generate MD5 message digests and check the result. Examples are "
+ "from RFC-1321."];
+md5(suite) ->
+ [];
+md5(Config) when is_list(Config) ->
+ ?line m(crypto:md5(""),
+ hexstr2bin("d41d8cd98f00b204e9800998ecf8427e")),
+ ?line m(crypto:md5("a"),
+ hexstr2bin("0cc175b9c0f1b6a831c399e269772661")),
+ ?line m(crypto:md5("abc"),
+ hexstr2bin("900150983cd24fb0d6963f7d28e17f72")),
+ ?line m(crypto:md5("message digest"),
+ hexstr2bin("f96b697d7cb7938d525a2f31aaf161d0")),
+ ?line m(crypto:md5("abcdefghijklmnopqrstuvwxyz"),
+ hexstr2bin("c3fcd3d76192e4007dfb496cca67e13b")),
+ ?line m(crypto:md5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789"),
+ hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")),
+ ?line m(crypto:md5("12345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890"),
+ hexstr2bin("57edf4a22be3c955ac49da2e2107b67a")).
+
+%%
+%%
+md5_update(doc) ->
+ ["Generate MD5 message using md5_init, md5_update, and md5_final, and"
+ "check the result. Examples are from RFC-1321."];
+md5_update(suite) ->
+ [];
+md5_update(Config) when is_list(Config) ->
+ ?line Ctx = crypto:md5_init(),
+ ?line Ctx1 = crypto:md5_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ ?line Ctx2 = crypto:md5_update(Ctx1, "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"),
+ ?line m(crypto:md5_final(Ctx2),
+ hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")).
+
+%%
+%%
+md4(doc) ->
+ ["Generate MD4 message digests and check the result. Examples are "
+ "from RFC-1321."];
+md4(suite) ->
+ [];
+md4(Config) when is_list(Config) ->
+ ?line m(crypto:md4(""),
+ hexstr2bin("31d6cfe0d16ae931b73c59d7e0c089c0")),
+ ?line m(crypto:md4("a"),
+ hexstr2bin("bde52cb31de33e46245e05fbdbd6fb24")),
+ ?line m(crypto:md4("abc"),
+ hexstr2bin("a448017aaf21d8525fc10ae87aa6729d")),
+ ?line m(crypto:md4("message digest"),
+ hexstr2bin("d9130a8164549fe818874806e1c7014b")),
+ ?line m(crypto:md4("abcdefghijklmnopqrstuvwxyz"),
+ hexstr2bin("d79e1c308aa5bbcdeea8ed63df412da9")),
+ ?line m(crypto:md4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789"),
+ hexstr2bin("043f8582f241db351ce627e153e7f0e4")),
+ ?line m(crypto:md4("12345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890"),
+ hexstr2bin("e33b4ddc9c38f2199c3e7b164fcc0536")).
+
+%%
+%%
+md4_update(doc) ->
+ ["Generate MD5 message using md5_init, md5_update, and md5_final, and"
+ "check the result. Examples are from RFC-1321."];
+md4_update(suite) ->
+ [];
+md4_update(Config) when is_list(Config) ->
+ ?line Ctx = crypto:md4_init(),
+ ?line Ctx1 = crypto:md4_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ ?line Ctx2 = crypto:md4_update(Ctx1, "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"),
+ ?line m(crypto:md4_final(Ctx2),
+ hexstr2bin("043f8582f241db351ce627e153e7f0e4")).
+
+%%
+%%
+sha(doc) ->
+ ["Generate SHA message digests and check the result. Examples are "
+ "from FIPS-180-1."];
+sha(suite) ->
+ [];
+sha(Config) when is_list(Config) ->
+ ?line m(crypto:sha("abc"),
+ hexstr2bin("A9993E364706816ABA3E25717850C26C9CD0D89D")),
+ ?line m(crypto:sha("abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ "nlmnomnopnopq"),
+ hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")).
+
+
+%%
+hmac_update_sha_n(doc) ->
+ ["Request a larger-than-allowed SHA1 HMAC using hmac_init, hmac_update, and hmac_final_n. "
+ "Expected values for examples are generated using crypto:sha_mac." ];
+hmac_update_sha_n(suite) ->
+ [];
+hmac_update_sha_n(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(sha, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final_n(Ctx3, 1024),
+ ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac),
+ ?line m(size(Exp), size(Mac)).
+
+
+hmac_update_sha(doc) ->
+ ["Generate an SHA1 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:sha_mac." ];
+hmac_update_sha(suite) ->
+ [];
+hmac_update_sha(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(sha, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final(Ctx3),
+ ?line Exp = crypto:hmac(sha, Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+
+hmac_update_sha256(doc) ->
+ ["Generate an SHA256 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:sha256_mac." ];
+hmac_update_sha256(suite) ->
+ [];
+hmac_update_sha256(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> hmac_update_sha256_do() end).
+
+hmac_update_sha256_do() ->
+ ?line Key = hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(sha256, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final(Ctx3),
+ ?line Exp = crypto:hmac(sha256, Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+
+hmac_update_sha512(doc) ->
+ ["Generate an SHA512 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:sha512_mac." ];
+hmac_update_sha512(suite) ->
+ [];
+hmac_update_sha512(Config) when is_list(Config) ->
+ if_supported(sha512, fun() -> hmac_update_sha512_do() end).
+
+hmac_update_sha512_do() ->
+ ?line Key = hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(sha512, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final(Ctx3),
+ ?line Exp = crypto:hmac(sha512, Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+
+hmac_update_md5(doc) ->
+ ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:md5_mac." ];
+hmac_update_md5(suite) ->
+ [];
+hmac_update_md5(Config) when is_list(Config) ->
+ % ?line Key2 = ["A fine speach", "by a fine man!"],
+ Key2 = "A fine speach by a fine man!",
+ ?line Long1 = "Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.",
+ ?line Long2 = "Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.",
+ ?line Long3 = "But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us-that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion that we here highly resolve that these dead shall not have died in vain-that this nation, under God, shall have a new birth of freedom-and that government of the people, by the people, for the people, shall not perish from the earth.",
+ ?line CtxA = crypto:hmac_init(md5, Key2),
+ ?line CtxB = crypto:hmac_update(CtxA, Long1),
+ ?line CtxC = crypto:hmac_update(CtxB, Long2),
+ ?line CtxD = crypto:hmac_update(CtxC, Long3),
+ ?line Mac2 = crypto:hmac_final(CtxD),
+ ?line Exp2 = crypto:md5_mac(Key2, lists:flatten([Long1, Long2, Long3])),
+ ?line m(Exp2, Mac2).
+
+hmac_rfc2202(doc) ->
+ ["Generate an HMAC using hmac, md5_mac, and sha_mac."
+ "Test vectors are taken from RFC-2202."];
+hmac_rfc2202(suite) ->
+ [];
+hmac_rfc2202(Config) when is_list(Config) ->
+ hmac_rfc2202_md5(),
+ hmac_rfc2202_sha().
+
+hmac_rfc2202_md5() ->
+ %% Test case 1
+ Case1Key = binary:copy(<<16#0b>>, 16),
+ Case1Data = <<"Hi There">>,
+ Case1Exp = hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d"),
+
+ ?line Case1Mac_1 = crypto:md5_mac(Case1Key, Case1Data),
+ ?line Case1Mac_2 = crypto:hmac(md5, Case1Key, Case1Data),
+ ?line m(Case1Exp, Case1Mac_1),
+ ?line m(Case1Exp, Case1Mac_2),
+
+ %% Test case 2
+ Case2Key = <<"Jefe">>,
+ Case2Data = <<"what do ya want for nothing?">>,
+ Case2Exp = hexstr2bin("750c783e6ab0b503eaa86e310a5db738"),
+
+ ?line Case2Mac_1 = crypto:md5_mac(Case2Key, Case2Data),
+ ?line Case2Mac_2 = crypto:hmac(md5, Case2Key, Case2Data),
+ ?line m(Case2Exp, Case2Mac_1),
+ ?line m(Case2Exp, Case2Mac_2),
+
+ %% Test case 3
+ Case3Key = binary:copy(<<16#aa>>, 16),
+ Case3Data = binary:copy(<<16#dd>>, 50),
+ Case3Exp = hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6"),
+
+ ?line Case3Mac_1 = crypto:md5_mac(Case3Key, Case3Data),
+ ?line Case3Mac_2 = crypto:hmac(md5, Case3Key, Case3Data),
+ ?line m(Case3Exp, Case3Mac_1),
+ ?line m(Case3Exp, Case3Mac_2),
+
+ %% Test case 4
+ Case4Key = list_to_binary(lists:seq(1, 16#19)),
+ Case4Data = binary:copy(<<16#cd>>, 50),
+ Case4Exp = hexstr2bin("697eaf0aca3a3aea3a75164746ffaa79"),
+
+ ?line Case4Mac_1 = crypto:md5_mac(Case4Key, Case4Data),
+ ?line Case4Mac_2 = crypto:hmac(md5, Case4Key, Case4Data),
+ ?line m(Case4Exp, Case4Mac_1),
+ ?line m(Case4Exp, Case4Mac_2),
+
+ %% Test case 5
+ Case5Key = binary:copy(<<16#0c>>, 16),
+ Case5Data = "Test With Truncation",
+ Case5Exp = hexstr2bin("56461ef2342edc00f9bab995690efd4c"),
+ Case5Exp96 = hexstr2bin("56461ef2342edc00f9bab995"),
+
+ ?line Case5Mac_1 = crypto:md5_mac(Case5Key, Case5Data),
+ ?line Case5Mac_2 = crypto:hmac(md5, Case5Key, Case5Data),
+ ?line Case5Mac96_1 = crypto:md5_mac_96(Case5Key, Case5Data),
+ ?line Case5Mac96_2 = crypto:hmac(md5, Case5Key, Case5Data, 12),
+ ?line m(Case5Exp, Case5Mac_1),
+ ?line m(Case5Exp, Case5Mac_2),
+ ?line m(Case5Exp96, Case5Mac96_1),
+ ?line m(Case5Exp96, Case5Mac96_2),
+
+ %% Test case 6
+ Case6Key = binary:copy(<<16#aa>>, 80),
+ Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ Case6Exp = hexstr2bin("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"),
+
+ ?line Case6Mac_1 = crypto:md5_mac(Case6Key, Case6Data),
+ ?line Case6Mac_2 = crypto:hmac(md5, Case6Key, Case6Data),
+ ?line m(Case6Exp, Case6Mac_1),
+ ?line m(Case6Exp, Case6Mac_2),
+
+ %% Test case 7
+ Case7Key = binary:copy(<<16#aa>>, 80),
+ Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
+ Case7Exp = hexstr2bin("6f630fad67cda0ee1fb1f562db3aa53e"),
+
+ ?line Case7Mac_1 = crypto:md5_mac(Case7Key, Case7Data),
+ ?line Case7Mac_2 = crypto:hmac(md5, Case7Key, Case7Data),
+ ?line m(Case7Exp, Case7Mac_1),
+ ?line m(Case7Exp, Case7Mac_2).
+
+hmac_rfc2202_sha() ->
+ %% Test case 1
+ Case1Key = binary:copy(<<16#0b>>, 20),
+ Case1Data = <<"Hi There">>,
+ Case1Exp = hexstr2bin("b617318655057264e28bc0b6fb378c8ef146be00"),
+
+ ?line Case1Mac_1 = crypto:sha_mac(Case1Key, Case1Data),
+ ?line Case1Mac_2 = crypto:hmac(sha, Case1Key, Case1Data),
+ ?line m(Case1Exp, Case1Mac_1),
+ ?line m(Case1Exp, Case1Mac_2),
+
+ %% Test case 2
+ Case2Key = <<"Jefe">>,
+ Case2Data = <<"what do ya want for nothing?">>,
+ Case2Exp = hexstr2bin("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"),
+
+ ?line Case2Mac_1 = crypto:sha_mac(Case2Key, Case2Data),
+ ?line Case2Mac_2 = crypto:hmac(sha, Case2Key, Case2Data),
+ ?line m(Case2Exp, Case2Mac_1),
+ ?line m(Case2Exp, Case2Mac_2),
+
+ %% Test case 3
+ Case3Key = binary:copy(<<16#aa>>, 20),
+ Case3Data = binary:copy(<<16#dd>>, 50),
+ Case3Exp = hexstr2bin("125d7342b9ac11cd91a39af48aa17b4f63f175d3"),
+
+ ?line Case3Mac_1 = crypto:sha_mac(Case3Key, Case3Data),
+ ?line Case3Mac_2 = crypto:hmac(sha, Case3Key, Case3Data),
+ ?line m(Case3Exp, Case3Mac_1),
+ ?line m(Case3Exp, Case3Mac_2),
+
+ %% Test case 4
+ Case4Key = list_to_binary(lists:seq(1, 16#19)),
+ Case4Data = binary:copy(<<16#cd>>, 50),
+ Case4Exp = hexstr2bin("4c9007f4026250c6bc8414f9bf50c86c2d7235da"),
+
+ ?line Case4Mac_1 = crypto:sha_mac(Case4Key, Case4Data),
+ ?line Case4Mac_2 = crypto:hmac(sha, Case4Key, Case4Data),
+ ?line m(Case4Exp, Case4Mac_1),
+ ?line m(Case4Exp, Case4Mac_2),
+
+ %% Test case 5
+ Case5Key = binary:copy(<<16#0c>>, 20),
+ Case5Data = "Test With Truncation",
+ Case5Exp = hexstr2bin("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
+ Case5Exp96 = hexstr2bin("4c1a03424b55e07fe7f27be1"),
+
+ ?line Case5Mac_1 = crypto:sha_mac(Case5Key, Case5Data),
+ ?line Case5Mac_2 = crypto:hmac(sha, Case5Key, Case5Data),
+ ?line Case5Mac96_1 = crypto:sha_mac_96(Case5Key, Case5Data),
+ ?line Case5Mac96_2 = crypto:hmac(sha, Case5Key, Case5Data, 12),
+ ?line m(Case5Exp, Case5Mac_1),
+ ?line m(Case5Exp, Case5Mac_2),
+ ?line m(Case5Exp96, Case5Mac96_1),
+ ?line m(Case5Exp96, Case5Mac96_2),
+
+ %% Test case 6
+ Case6Key = binary:copy(<<16#aa>>, 80),
+ Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ Case6Exp = hexstr2bin("aa4ae5e15272d00e95705637ce8a3b55ed402112"),
+
+ ?line Case6Mac_1 = crypto:sha_mac(Case6Key, Case6Data),
+ ?line Case6Mac_2 = crypto:hmac(sha, Case6Key, Case6Data),
+ ?line m(Case6Exp, Case6Mac_1),
+ ?line m(Case6Exp, Case6Mac_2),
+
+ %% Test case 7
+ Case7Key = binary:copy(<<16#aa>>, 80),
+ Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
+ Case7Exp = hexstr2bin("e8e99d0f45237d786d6bbaa7965c7808bbff1a91"),
+
+ ?line Case7Mac_1 = crypto:sha_mac(Case7Key, Case7Data),
+ ?line Case7Mac_2 = crypto:hmac(sha, Case7Key, Case7Data),
+ ?line m(Case7Exp, Case7Mac_1),
+ ?line m(Case7Exp, Case7Mac_2).
+
+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_sha224(suite) ->
+ [];
+hmac_rfc4231_sha224(Config) when is_list(Config) ->
+ if_supported(sha224, fun() -> hmac_rfc4231_sha224_do() end).
+
+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, case1, Exp) ->
+ %% Test 1
+ Key = binary:copy(<<16#0b>>, 20),
+ Data = <<"Hi There">>,
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case2, Exp) ->
+ %% Test 2
+ Key = <<"Jefe">>,
+ Data = <<"what do ya want for nothing?">>,
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case3, Exp) ->
+ %% Test 3
+ Key = binary:copy(<<16#aa>>, 20),
+ Data = binary:copy(<<16#dd>>, 50),
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case4, Exp) ->
+ %% Test 4
+ Key = list_to_binary(lists:seq(1, 16#19)),
+ Data = binary:copy(<<16#cd>>, 50),
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case5, Exp) ->
+ %% Test 5
+ Key = binary:copy(<<16#0c>>, 20),
+ Data = <<"Test With Truncation">>,
+ hmac_rfc4231_case(Hash, Key, Data, 16, Exp);
+
+hmac_rfc4231_case(Hash, case6, Exp) ->
+ %% Test 6
+ Key = binary:copy(<<16#aa>>, 131),
+ Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case7, Exp) ->
+ %% Test Case 7
+ Key = binary:copy(<<16#aa>>, 131),
+ Data = <<"This is a test using a larger than block-size key and a larger t",
+ "han block-size data. The key needs to be hashed before being use",
+ "d by the HMAC algorithm.">>,
+ hmac_rfc4231_case(Hash, Key, Data, Exp).
+
+hmac_rfc4231_case(Hash, Key, Data, Exp) ->
+ ?line Ctx = crypto:hmac_init(Hash, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Mac1 = crypto:hmac_final(Ctx2),
+ ?line Mac3 = crypto:hmac(Hash, Key, Data),
+ ?line m(Exp, Mac1),
+ ?line m(Exp, Mac3).
+
+hmac_rfc4231_case(Hash, Key, Data, Trunc, Exp) ->
+ ?line Ctx = crypto:hmac_init(Hash, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Mac1 = crypto:hmac_final_n(Ctx2, Trunc),
+ ?line Mac3 = crypto:hmac(Hash, Key, Data, Trunc),
+ ?line m(Exp, Mac1),
+ ?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, [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, [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, [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, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_cases_do(Hash, CasesData) ->
+ hmac_rfc4231_cases_do(Hash, [case1, case2, case3, case4, case5, case6, case7], CasesData).
+
+hmac_rfc4231_cases_do(_Hash, _, []) ->
+ ok;
+hmac_rfc4231_cases_do(Hash, [C|Cases], [D|CasesData]) ->
+ hmac_rfc4231_case(Hash, C, D),
+ hmac_rfc4231_cases_do(Hash, Cases, CasesData).
+
+hmac_update_md5_io(doc) ->
+ ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:md5_mac." ];
+hmac_update_md5_io(suite) ->
+ [];
+hmac_update_md5_io(Config) when is_list(Config) ->
+ ?line Key = ["A fine speach", "by a fine man!"],
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(md5, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final(Ctx3),
+ ?line Exp = crypto:md5_mac(Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+
+
+hmac_update_md5_n(doc) ->
+ ["Generate a shortened MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:md5_mac." ];
+hmac_update_md5_n(suite) ->
+ [];
+hmac_update_md5_n(Config) when is_list(Config) ->
+ ?line Key = ["A fine speach", "by a fine man!"],
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(md5, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final_n(Ctx3, 12),
+ ?line Exp = crypto:md5_mac_96(Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+%%
+%%
+ripemd160(doc) ->
+ ["Generate RIPEMD160 message digests and check the result."];
+ripemd160(suite) ->
+ [];
+ripemd160(Config) when is_list(Config) ->
+ ?line m(crypto:hash(ripemd160,"abc"),
+ hexstr2bin("8EB208F7E05D987A9B044A8E98C6B087F15A0BFC")),
+ ?line m(crypto:hash(ripemd160,"abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ "nlmnomnopnopq"),
+ hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
+
+
+%%
+%%
+ripemd160_update(doc) ->
+ ["Generate RIPEMD160 message digests by using ripemd160_init,"
+ "ripemd160_update, and ripemd160_final and check the result."];
+ripemd160_update(suite) ->
+ [];
+ripemd160_update(Config) when is_list(Config) ->
+ ?line Ctx = crypto:hash_init(ripemd160),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:hash_final(Ctx2),
+ hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
+
+%%
+%%
+sha_update(doc) ->
+ ["Generate SHA message digests by using sha_init, sha_update, and"
+ "sha_final, and check the result. Examples are from FIPS-180-1."];
+sha_update(suite) ->
+ [];
+sha_update(Config) when is_list(Config) ->
+ ?line Ctx = crypto:sha_init(),
+ ?line Ctx1 = crypto:sha_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:sha_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:sha_final(Ctx2),
+ hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")).
+
+%%
+%%
+sha256(doc) ->
+ ["Generate SHA-256 message digests and check the result. Examples are "
+ "from rfc-4634."];
+sha256(suite) ->
+ [];
+sha256(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> sha256_do() end).
+
+sha256_do() ->
+ ?line m(crypto:hash(sha256, "abc"),
+ hexstr2bin("BA7816BF8F01CFEA4141"
+ "40DE5DAE2223B00361A396177A9CB410FF61F20015AD")),
+ ?line m(crypto:hash(sha256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ "nlmnomnopnopq"),
+ hexstr2bin("248D6A61D20638B8"
+ "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
+
+%%
+%%
+sha256_update(doc) ->
+ ["Generate SHA256 message digests by using sha256_init, sha256_update, and"
+ "sha256_final, and check the result. Examples are from rfc-4634."];
+sha256_update(suite) ->
+ [];
+sha256_update(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> sha256_update_do() end).
+
+sha256_update_do() ->
+ ?line Ctx = crypto:hash_init(sha256),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:hash_final(Ctx2),
+ hexstr2bin("248D6A61D20638B8"
+ "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
+
+
+%%
+%%
+sha512(doc) ->
+ ["Generate SHA-512 message digests and check the result. Examples are "
+ "from rfc-4634."];
+sha512(suite) ->
+ [];
+sha512(Config) when is_list(Config) ->
+ if_supported(sha512, fun() -> sha512_do() end).
+
+sha512_do() ->
+ ?line m(crypto:hash(sha512, "abc"),
+ hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
+ "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
+ "454D4423643CE80E2A9AC94FA54CA49F")),
+ ?line m(crypto:hash(sha512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
+ hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
+ "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
+ "C7D329EEB6DD26545E96E55B874BE909")).
+
+%%
+%%
+sha512_update(doc) ->
+ ["Generate SHA512 message digests by using sha512_init, sha512_update, and"
+ "sha512_final, and check the result. Examples are from rfc=4634."];
+sha512_update(suite) ->
+ [];
+sha512_update(Config) when is_list(Config) ->
+ if_supported(sha512, fun() -> sha512_update_do() end).
+
+sha512_update_do() ->
+ ?line Ctx = crypto:hash_init(sha512),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
+ ?line m(crypto:hash_final(Ctx2),
+ hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
+ "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
+ "C7D329EEB6DD26545E96E55B874BE909")).
+
+%%
+%%
+md5_mac(doc) ->
+ ["Generate some HMACs, using MD5, and check the result. Examples are "
+ "from RFC-2104."];
+md5_mac(suite) ->
+ [];
+md5_mac(Config) when is_list(Config) ->
+ ?line m(crypto:md5_mac(hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ "Hi There"),
+ hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")),
+ ?line m(crypto:md5_mac(list_to_binary("Jefe"),
+ "what do ya want for nothing?"),
+ hexstr2bin("750c783e6ab0b503eaa86e310a5db738")),
+ ?line m(crypto:md5_mac(hexstr2bin("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
+ hexstr2bin("DDDDDDDDDDDDDDDDDDDD"
+ "DDDDDDDDDDDDDDDDDDDD"
+ "DDDDDDDDDDDDDDDDDDDD"
+ "DDDDDDDDDDDDDDDDDDDD"
+ "DDDDDDDDDDDDDDDDDDDD")),
+ hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6")).
+
+%%
+%%
+md5_mac_io(doc) ->
+ ["Generate some HMACs, using MD5, with Key an IO-list, and check the "
+ "result. Examples are from RFC-2104."];
+md5_mac_io(suite) ->
+ [];
+md5_mac_io(Config) when is_list(Config) ->
+ ?line Key1 = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ ?line {B11, B12} = split_binary(Key1, 4),
+ ?line Key11 = [B11,binary_to_list(B12)],
+ ?line m(crypto:md5_mac(Key11, "Hi There"),
+ hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")).
+
+%%
+%%
+des_cbc(doc) ->
+ "Encrypt and decrypt according to CBC DES. and check the result. "
+ "Example are from FIPS-81.";
+des_cbc(suite) ->
+ [];
+des_cbc(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the time for all ",
+ ?line Cipher = crypto:des_cbc_encrypt(Key, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
+ "0f683788499a7c05f6")),
+ ?line m(list_to_binary(Plain),
+ crypto:des_cbc_decrypt(Key, IVec, Cipher)),
+ ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
+ ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec, Plain2),
+ ?line m(Cipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9"
+ "9484521388fa59ae67d58d2e77e86062733")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des_cbc_decrypt(Key, IVec, Cipher2)).
+
+%%
+%%
+des_cbc_iter(doc) ->
+ "Encrypt and decrypt according to CBC DES in two steps, and "
+ "check the result. Example are from FIPS-81.";
+des_cbc_iter(suite) ->
+ [];
+des_cbc_iter(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain1 = "Now is the time ",
+ ?line Plain2 = "for all ",
+ ?line Cipher1 = crypto:des_cbc_encrypt(Key, IVec, Plain1),
+ ?line IVec2 = crypto:des_cbc_ivec(Cipher1),
+ ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec2, Plain2),
+ ?line Cipher = list_to_binary([Cipher1, Cipher2]),
+ ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
+ "0f683788499a7c05f6")).
+
+%%
+%%
+des_cfb(doc) ->
+ "Encrypt and decrypt according to CFB DES. and check the result. "
+ "Example is from FIPS-81.";
+des_cfb(suite) ->
+ [];
+des_cfb(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the",
+ ?line Cipher = crypto:des_cfb_encrypt(Key, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")),
+ ?line m(list_to_binary(Plain),
+ crypto:des_cfb_decrypt(Key, IVec, Cipher)).
+
+%%
+%%
+des_cfb_iter(doc) ->
+ "Encrypt and decrypt according to CFB DES in two steps, and "
+ "check the result. Example is from FIPS-81.";
+des_cfb_iter(suite) ->
+ [];
+des_cfb_iter(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain1 = "Now i",
+ ?line Plain2 = "s the",
+ ?line Cipher1 = crypto:des_cfb_encrypt(Key, IVec, Plain1),
+ ?line IVec2 = crypto:des_cfb_ivec(IVec, Cipher1),
+ ?line Cipher2 = crypto:des_cfb_encrypt(Key, IVec2, Plain2),
+ ?line Cipher = list_to_binary([Cipher1, Cipher2]),
+ ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")).
+
+%%
+%%
+des_ecb(doc) ->
+ "Encrypt and decrypt according to ECB DES and check the result. "
+ "Example are from FIPS-81.";
+des_ecb(suite) ->
+ [];
+des_ecb(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line Cipher1 = crypto:des_ecb_encrypt(Key, "Now is t"),
+ ?line m(Cipher1, hexstr2bin("3fa40e8a984d4815")),
+ ?line Cipher2 = crypto:des_ecb_encrypt(Key, "he time "),
+ ?line m(Cipher2, hexstr2bin("6a271787ab8883f9")),
+ ?line Cipher3 = crypto:des_ecb_encrypt(Key, "for all "),
+ ?line m(Cipher3, hexstr2bin("893d51ec4b563b53")),
+ ?line Cipher4 = crypto:des_ecb_decrypt(Key, hexstr2bin("3fa40e8a984d4815")),
+ ?line m(Cipher4, <<"Now is t">>),
+ ?line Cipher5 = crypto:des_ecb_decrypt(Key, hexstr2bin("6a271787ab8883f9")),
+ ?line m(Cipher5, <<"he time ">>),
+ ?line Cipher6 = crypto:des_ecb_decrypt(Key, hexstr2bin("893d51ec4b563b53")),
+ ?line m(Cipher6, <<"for all ">>).
+%%
+%%
+rc2_cbc(doc) ->
+ "Encrypt and decrypt according to RC2 CBC and check the result. "
+ "Example stripped out from public_key application test";
+rc2_cbc(Config) when is_list(Config) ->
+
+ Key = <<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
+ IV = <<72,91,135,182,25,42,35,210>>,
+
+ Cipher = <<36,245,206,158,168,230,58,69,148,137,32,192,250,41,237,181,181,251, 192,2,175,135,177,171,57,30,111,117,159,149,15,28,88,158,28,81,28,115, 85,219,241,82,117,222,91,85,73,117,164,25,182,52,191,64,123,57,26,19, 211,27,253,31,194,219,231,104,247,240,172,130,119,21,225,154,101,247, 32,216,42,216,133,169,78,22,97,27,227,26,196,224,172,168,17,9,148,55, 203,91,252,40,61,226,236,221,215,160,78,63,13,181,68,57,196,241,185, 207, 116,129,152,237,60,139,247,153,27,146,161,246,222,98,185,222,152, 187,135, 236,86,34,7,110,91,230,173,34,160,242,202,222,121,127,181,140, 101,203,195, 190,88,250,86,147,127,87,72,126,171,16,71,47,110,248,88, 14,29,143,161,152, 129,236,148,22,152,186,208,119,70,8,174,193,203,100, 193,203,200,117,102,242, 134,142,96,125,135,200,217,190,76,117,50,70, 209,186,101,241,200,91,40,193,54, 90,195,38,47,59,197,38,234,86,223,16, 51,253,204,129,20,171,66,21,241,26,135,216, 196,114,110,91,15,53,40, 164,201,136,113,95,247,51,181,208,241,68,168,98,151,36, 155,72,24,57, 42,191,14,125,204,10,167,214,233,138,115,125,234,121,134,227,26,247, 77,200,117,110,117,111,168,156,206,67,159,149,189,173,150,193,91,199, 216,153,22, 189,137,185,89,160,13,131,132,58,109,28,110,246,252,251,14, 232,91,38,52,29,101,188,69,123,50,0,130,178,93,73,239,118,7,77,35,59, 253,10,159,45,86,142,37,78,232,48>>,
+ Text = <<48,130,1,85,2,1,0,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,4,130,1,63,48,130, 1,59,2,1,0,2,65,0,222,187,252,44,9,214,27,173,162,169,70,47,36,34,78,84,204, 107,60,192,117,95,21,206,49,142,245,126,121,223,23,2,107,106,133,204,161,36, 40,2,114,69,4,93,242,5,42,50,154,47,154,211,209,123,120,161,5,114,173,155,34, 191,52,59,2,3,1,0,1,2,64,45,144,169,106,220,236,71,39,67,82,123,192,35,21,61, 143,13,110,150,180,12,142,210,40,39,109,70,125,132,51,6,66,159,134,112,85, 155,243,118,221,65,133,127,99,151,194,252,141,149,224,229,62,214,45,228,32, 184,85,67,14,228,161,184,161,2,33,0,255,202,240,131,130,57,49,224,115,255,83, 79,6,165,212,21,179,212,20,188,97,74,69,68,163,223,247,237,39,24,23,235,2,33, 0,222,234,48,36,33,23,219,45,59,136,55,245,143,29,165,48,255,131,207,146,131, 104,13,163,54,131,236,78,88,54,16,241,2,33,0,230,2,99,129,173,176,166,131, 241,106,143,76,9,107,70,41,121,185,228,39,124,200,159,62,216,169,5,180,111, 169,255,159,2,33,0,151,193,70,212,209,210,179,219,175,83,165,4,255,81,103,76, 92,39,24,0,222,132,208,3,244,241,10,198,171,54,227,129,2,32,43,250,20,31,16, 189,168,116,225,1,125,132,94,130,118,124,28,56,232,39,69,218,244,33,240,200, 205,9,215,101,35,135,7,7,7,7,7,7,7>>,
+
+ Text = crypto:rc2_cbc_decrypt(Key, IV, Cipher),
+ Cipher = crypto:rc2_cbc_encrypt(Key, IV, Text).
+
+%%
+%%
+des3_cbc(doc) ->
+ "Encrypt and decrypt according to CBC 3DES, and check the result.";
+des3_cbc(suite) ->
+ [];
+des3_cbc(Config) when is_list(Config) ->
+ ?line Key1 = hexstr2bin("0123456789abcdef"),
+ ?line Key2 = hexstr2bin("fedcba9876543210"),
+ ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the time for all ",
+ ?line Cipher = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("8a2667ee5577267cd9b1af2c5a0480"
+ "0bac1ae66970fb2b89")),
+ ?line m(list_to_binary(Plain),
+ crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher)),
+ ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
+ ?line Cipher2 = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain2),
+ ?line m(Cipher2, hexstr2bin("eb33ec6ede2c8e90f6877e77b95d5"
+ "4c83cee22907f7f0041ca1b7abe202bfafe")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher2)),
+
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line DESCipher = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain),
+ ?line m(DESCipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
+ "0f683788499a7c05f6")),
+ ?line m(list_to_binary(Plain),
+ crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher)),
+ ?line DESCipher2 = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain2),
+ ?line m(DESCipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9"
+ "9484521388fa59ae67d58d2e77e86062733")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher2)).
+
+%%
+%%
+des3_cfb(doc) ->
+ "Encrypt and decrypt according to CFB 3DES, and check the result.";
+des3_cfb(suite) ->
+ [];
+des3_cfb(Config) when is_list(Config) ->
+ case openssl_version() of
+ V when V < 16#90705F -> {skipped,"OpenSSL version too old"};
+ _ -> des3_cfb_do()
+ end.
+
+des3_cfb_do() ->
+ ?line Key1 = hexstr2bin("0123456789abcdef"),
+ ?line Key2 = hexstr2bin("fedcba9876543210"),
+ ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the time for all ",
+ ?line Cipher = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("fc0ba7a20646ba53cc8bff263f0937"
+ "1deab42a00666db02c")),
+ ?line m(list_to_binary(Plain),
+ crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher)),
+ ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
+ ?line Cipher2 = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain2),
+ ?line m(Cipher2, hexstr2bin("8582c59ac01897422632c0accb66c"
+ "e413f5efab838fce7e41e2ba67705bad5bc")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher2)).
+
+%%
+%%
+aes_cfb(doc) ->
+ "Encrypt and decrypt according to AES CFB 128 bit and check "
+ "the result. Example are from NIST SP 800-38A.";
+
+aes_cfb(suite) ->
+ [];
+aes_cfb(Config) when is_list(Config) ->
+
+%% Sample data from NIST Spec.Publ. 800-38A
+%% F.3.13 CFB128-AES128.Encrypt
+%% Key 2b7e151628aed2a6abf7158809cf4f3c
+%% IV 000102030405060708090a0b0c0d0e0f
+%% Segment #1
+%% Input Block 000102030405060708090a0b0c0d0e0f
+%% Output Block 50fe67cc996d32b6da0937e99bafec60
+%% Plaintext 6bc1bee22e409f96e93d7e117393172a
+%% Ciphertext 3b3fd92eb72dad20333449f8e83cfb4a
+%% Segment #2
+%% Input Block 3b3fd92eb72dad20333449f8e83cfb4a
+%% Output Block 668bcf60beb005a35354a201dab36bda
+%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+%% Ciphertext c8a64537a0b3a93fcde3cdad9f1ce58b
+%% Segment #3
+%% Input Block c8a64537a0b3a93fcde3cdad9f1ce58b
+%% Output Block 16bd032100975551547b4de89daea630
+%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+%% Ciphertext 26751f67a3cbb140b1808cf187a4f4df
+%% Segment #4
+%% Input Block 26751f67a3cbb140b1808cf187a4f4df
+%% Output Block 36d42170a312871947ef8714799bc5f6
+%% Plaintext f69f2445df4f9b17ad2b417be66c3710
+%% Ciphertext c04b05357c5d1c0eeac4c66f9ff7f2e6
+
+ ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"),
+ ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"),
+ ?line Cipher = hexstr2bin("3b3fd92eb72dad20333449f8e83cfb4a"),
+
+ %% Try all prefixes of plain and cipher.
+ aes_cfb_do(byte_size(Plain), Plain, Cipher, Key, IVec).
+
+aes_cfb_do(N, Plain, Cipher, Key, IVec) when N >= 0 ->
+ <<P:N/binary, _/binary>> = Plain,
+ <<C:N/binary, _/binary>> = Cipher,
+ ?line C = crypto:aes_cfb_128_encrypt(Key, IVec, P),
+ ?line P = crypto:aes_cfb_128_decrypt(Key, IVec, C),
+ aes_cfb_do(N-1, Plain, Cipher, Key, IVec);
+aes_cfb_do(_, _, _, _, _) -> ok.
+
+
+%%
+%%
+aes_cbc(doc) ->
+ "Encrypt and decrypt according to AES CBC 128 bit. and check the result. "
+ "Example are from NIST SP 800-38A.";
+
+aes_cbc(suite) ->
+ [];
+aes_cbc(Config) when is_list(Config) ->
+
+%% Sample data from NIST Spec.Publ. 800-38A
+%% F.2.1 CBC-AES128.Encrypt
+%% Key 2b7e151628aed2a6abf7158809cf4f3c
+%% IV 000102030405060708090a0b0c0d0e0f
+%% Block #1
+%% Plaintext 6bc1bee22e409f96e93d7e117393172a
+%% Input Block 6bc0bce12a459991e134741a7f9e1925
+%% Output Block 7649abac8119b246cee98e9b12e9197d
+%% Ciphertext 7649abac8119b246cee98e9b12e9197d
+%% Block #2
+%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+%% Input Block d86421fb9f1a1eda505ee1375746972c
+%% Output Block 5086cb9b507219ee95db113a917678b2
+%% Ciphertext 5086cb9b507219ee95db113a917678b2
+%% Block #3
+%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+%% Input Block 604ed7ddf32efdff7020d0238b7c2a5d
+%% Output Block 73bed6b8e3c1743b7116e69e22229516
+%% Ciphertext 73bed6b8e3c1743b7116e69e22229516
+%% Block #4
+%% Plaintext f69f2445df4f9b17ad2b417be66c3710
+%% Input Block 8521f2fd3c8eef2cdc3da7e5c44ea206
+%% Output Block 3ff1caa1681fac09120eca307586e1a7
+%% Ciphertext 3ff1caa1681fac09120eca307586e1a7
+%%
+%% F.2.2 CBC-AES128.Decrypt
+%% Key 2b7e151628aed2a6abf7158809cf4f3c
+%% IV 000102030405060708090a0b0c0d0e0f
+ %% Block #1
+%% Ciphertext 7649abac8119b246cee98e9b12e9197d
+%% Input Block 7649abac8119b246cee98e9b12e9197d
+%% Output Block 6bc0bce12a459991e134741a7f9e1925
+%% Plaintext 6bc1bee22e409f96e93d7e117393172a
+%% Block #2
+%% Ciphertext 5086cb9b507219ee95db113a917678b2
+%% Input Block 5086cb9b507219ee95db113a917678b2
+%% Output Block d86421fb9f1a1eda505ee1375746972c
+%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+%% Block #3
+%% Ciphertext 73bed6b8e3c1743b7116e69e22229516
+%% Input Block 73bed6b8e3c1743b7116e69e22229516
+%% Output Block 604ed7ddf32efdff7020d0238b7c2a5d
+%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+%% Block #4
+%% Ciphertext 3ff1caa1681fac09120eca307586e1a7
+%% Input Block 3ff1caa1681fac09120eca307586e1a7
+%% Output Block 8521f2fd3c8eef2cdc3da7e5c44ea206
+%% Plaintext f69f2445df4f9b17ad2b417be66c3710
+
+ ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"),
+ ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"),
+ ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("7649abac8119b246cee98e9b12e9197d")),
+ ?line m(Plain,
+ crypto:aes_cbc_128_decrypt(Key, IVec, Cipher)).
+
+aes_cbc_iter(doc) ->
+ "Encrypt and decrypt according to CBC AES in steps";
+aes_cbc_iter(suite) -> [];
+aes_cbc_iter(Config) when is_list(Config) ->
+ Key = list_to_binary(lists:seq(255,256-16*17,-17)),
+ IVec = list_to_binary(lists:seq(1,16*7,7)),
+ Plain = <<"One, two, three o'clock, four o'clock, rock"
+ "Five, six, seven o'clock, eight o'clock, rock"
+ "Nine, ten, eleven o'clock, twelve o'clock, rock"
+ "We're gonna rock around the clock tonight">>,
+ ?line 0 = size(Plain) rem 16,
+
+ ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain),
+ ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Cipher),
+
+ ?line Cipher = aes_cbc_encrypt_iter(Key,IVec,Plain,<<>>),
+ ?line Plain = aes_cbc_decrypt_iter(Key,IVec,Cipher,<<>>),
+ ok.
+
+aes_cbc_encrypt_iter(_,_,<<>>, Acc) ->
+ Acc;
+aes_cbc_encrypt_iter(Key,IVec,Data, Acc) ->
+ Bytes = 16 * (1 + size(Data) div (16*3)),
+ <<Chunk:Bytes/binary, Rest/binary>> = Data,
+ %%io:format("encrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]),
+ ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Chunk),
+ ?line IVec2 = crypto:aes_cbc_ivec(Cipher),
+ aes_cbc_encrypt_iter(Key,IVec2,Rest, <<Acc/binary, Cipher/binary>>).
+
+aes_cbc_decrypt_iter(_,_,<<>>, Acc) ->
+ Acc;
+aes_cbc_decrypt_iter(Key,IVec,Data, Acc) ->
+ Bytes = 16 * (1 + size(Data) div (16*5)),
+ <<Chunk:Bytes/binary, Rest/binary>> = Data,
+ %%io:format("decrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]),
+ ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Chunk),
+ ?line IVec2 = crypto:aes_cbc_ivec(Chunk),
+ aes_cbc_decrypt_iter(Key,IVec2,Rest, <<Acc/binary, Plain/binary>>).
+
+
+aes_ctr(doc) -> "CTR";
+aes_ctr(Config) when is_list(Config) ->
+ %% Sample data from NIST Spec.Publ. 800-38A
+ %% F.5.1 CTR-AES128.Encrypt
+ Key128 = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ Samples128 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ "6bc1bee22e409f96e93d7e117393172a", % Plaintext
+ "874d6191b620e3261bef6864990db6ce"},% Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ "ae2d8a571e03ac9c9eb76fac45af8e51",
+ "9806f66b7970fdff8617187bb9fffdff"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ "30c81c46a35ce411e5fbc1191a0a52ef",
+ "5ae4df3edbd5d35e5b4f09020db03eab"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ "f69f2445df4f9b17ad2b417be66c3710",
+ "1e031dda2fbe03d1792170a0f3009cee"}],
+ lists:foreach(fun(S) -> aes_ctr_do(Key128,S) end, Samples128),
+
+ %% F.5.3 CTR-AES192.Encrypt
+ Key192 = hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ Samples192 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ "6bc1bee22e409f96e93d7e117393172a", % Plaintext
+ "1abc932417521ca24f2b0459fe7e6e0b"},% Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ "ae2d8a571e03ac9c9eb76fac45af8e51",
+ "090339ec0aa6faefd5ccc2c6f4ce8e94"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ "30c81c46a35ce411e5fbc1191a0a52ef",
+ "1e36b26bd1ebc670d1bd1d665620abf7"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ "f69f2445df4f9b17ad2b417be66c3710",
+ "4f78a7f6d29809585a97daec58c6b050"}],
+ lists:foreach(fun(S) -> aes_ctr_do(Key192,S) end, Samples192),
+
+ %% F.5.5 CTR-AES256.Encrypt
+ Key256 = hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ Samples256 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ "6bc1bee22e409f96e93d7e117393172a", % Plaintext
+ "601ec313775789a5b7a7f504bbf3d228"},% Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ "ae2d8a571e03ac9c9eb76fac45af8e51",
+ "f443e3ca4d62b59aca84e990cacaf5c5"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ "30c81c46a35ce411e5fbc1191a0a52ef",
+ "2b0930daa23de94ce87017ba2d84988d"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ "f69f2445df4f9b17ad2b417be66c3710",
+ "dfc9c58db67aada613c2dd08457941a6"}],
+ lists:foreach(fun(S) -> aes_ctr_do(Key256,S) end, Samples256).
+
+
+aes_ctr_do(Key,{IVec, Plain, Cipher}) ->
+ ?line I = hexstr2bin(IVec),
+ ?line P = hexstr2bin(Plain),
+ ?line C = crypto:aes_ctr_encrypt(Key, I, P),
+ ?line m(C, hexstr2bin(Cipher)),
+ ?line m(P, crypto:aes_ctr_decrypt(Key, I, C)).
+
+aes_ctr_stream(doc) -> "CTR Streaming";
+aes_ctr_stream(Config) when is_list(Config) ->
+ %% Sample data from NIST Spec.Publ. 800-38A
+ %% F.5.1 CTR-AES128.Encrypt
+ Key128 = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ Samples128 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ ["6bc1bee22e409f", "96e93d7e117393172a"], % Plaintext
+ ["874d6191b620e3261bef6864990db6ce"]}, % Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ ["ae2d8a57", "1e03ac9c", "9eb76fac", "45af8e51"],
+ ["9806f66b7970fdff","8617187bb9fffdff"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ ["30c81c46a35c", "e411e5fbc119", "1a0a52ef"],
+ ["5ae4df3e","dbd5d3","5e5b4f0902","0db03eab"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ ["f69f2445df4f9b17ad2b417be66c3710"],
+ ["1e031dda2fbe","03d1792170a0","f3009cee"]}],
+ lists:foreach(fun(S) -> aes_ctr_stream_do(Key128,S) end, Samples128),
+
+ %% F.5.3 CTR-AES192.Encrypt
+ Key192 = hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ Samples192 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ ["6bc1bee22e409f96e93d7e117393172a"], % Plaintext
+ ["1abc9324","17521c","a24f2b04","59fe7e6e0b"]}, % Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ ["ae2d8a57", "1e03ac9c9eb76fac", "45af8e51"],
+ ["090339ec0aa6faefd5ccc2c6f4ce8e94"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ ["30c81c46a35ce411", "e5fbc1191a0a52ef"],
+ ["1e36b26bd1","ebc670d1bd1d","665620abf7"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ ["f69f2445", "df4f9b17ad", "2b417be6", "6c3710"],
+ ["4f78a7f6d2980958","5a97daec58c6b050"]}],
+ lists:foreach(fun(S) -> aes_ctr_stream_do(Key192,S) end, Samples192),
+
+ %% F.5.5 CTR-AES256.Encrypt
+ Key256 = hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ Samples256 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ ["6bc1bee22e409f96", "e93d7e117393172a"], % Plaintext
+ ["601ec313775789", "a5b7a7f504bbf3d228"]}, % Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ ["ae2d8a571e03ac9c9eb76fac45af8e51"],
+ ["f443e3ca","4d62b59aca84","e990cacaf5c5"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ ["30c81c46","a35ce411","e5fbc119","1a0a52ef"],
+ ["2b0930daa23de94ce87017ba2d84988d"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ ["f69f2445df4f","9b17ad2b41","7be66c3710"],
+ ["dfc9c5","8db67aada6","13c2dd08","457941a6"]}],
+ lists:foreach(fun(S) -> aes_ctr_stream_do(Key256,S) end, Samples256).
+
+
+aes_ctr_stream_do(Key,{IVec, PlainList, CipherList}) ->
+ ?line I = hexstr2bin(IVec),
+ ?line S = crypto:aes_ctr_stream_init(Key, I),
+ ?line C = aes_ctr_stream_do_iter(
+ S, PlainList, [],
+ fun(S2,P) -> crypto:aes_ctr_stream_encrypt(S2, P) end),
+ ?line m(C, hexstr2bin(lists:flatten(CipherList))),
+ ?line P = aes_ctr_stream_do_iter(
+ S, CipherList, [],
+ fun(S2,C2) -> crypto:aes_ctr_stream_decrypt(S2, C2) end),
+ ?line m(P, hexstr2bin(lists:flatten(PlainList))).
+
+aes_ctr_stream_do_iter(_State, [], Acc, _CipherFun) ->
+ iolist_to_binary(lists:reverse(Acc));
+aes_ctr_stream_do_iter(State, [Plain|Rest], Acc, CipherFun) ->
+ ?line P = hexstr2bin(Plain),
+ ?line {S2, C} = CipherFun(State, P),
+ aes_ctr_stream_do_iter(S2, Rest, [C | Acc], CipherFun).
+
+%%
+%%
+mod_exp_test(doc) ->
+ "mod_exp testing (A ^ M % P with bignums)";
+mod_exp_test(suite) ->
+ [];
+mod_exp_test(Config) when is_list(Config) ->
+ mod_exp_aux_test(2, 5, 10, 8).
+
+mod_exp_aux_test(_, _, _, 0) ->
+ ok;
+mod_exp_aux_test(B, E, M, N) ->
+ ?line R1 = crypto:mod_exp(B, E, M),
+ ?line R2 = ipow(B, E, M),
+ ?line m(R1, R2),
+ ?line mod_exp_aux_test(B, E*E+1, M*M+1, N-1).
+
+%%
+%%
+rand_uniform_test(doc) ->
+ "rand_uniform and random_bytes testing";
+rand_uniform_test(suite) ->
+ [];
+rand_uniform_test(Config) when is_list(Config) ->
+ rand_uniform_aux_test(10),
+ ?line 10 = size(crypto:rand_bytes(10)).
+
+rand_uniform_aux_test(0) ->
+ ok;
+rand_uniform_aux_test(N) ->
+ ?line L = N*1000,
+ ?line H = N*100000+1,
+ ?line crypto_rand_uniform(L, H),
+ ?line crypto_rand_uniform(-L, L),
+ ?line crypto_rand_uniform(-H, -L),
+ ?line crypto_rand_uniform(-H, L),
+ ?line rand_uniform_aux_test(N-1).
+
+crypto_rand_uniform(L,H) ->
+ ?line R1 = crypto:rand_uniform(L, H),
+ ?line t(R1 >= L),
+ ?line t(R1 < H).
+
+
+%%
+%%
+strong_rand_test(doc) ->
+ "strong_rand_mpint and strong_random_bytes testing";
+strong_rand_test(suite) ->
+ [];
+strong_rand_test(Config) when is_list(Config) ->
+ strong_rand_aux_test(180),
+ ?line 10 = byte_size(crypto:strong_rand_bytes(10)).
+
+strong_rand_aux_test(0) ->
+ ?line t(crypto:strong_rand_mpint(0,0,0) =:= <<0,0,0,0>>),
+ ok;
+strong_rand_aux_test(1) ->
+ ?line t(crypto:erlint(crypto:strong_rand_mpint(1,0,1)) =:= 1),
+ ?line strong_rand_aux_test(0);
+strong_rand_aux_test(N) ->
+ ?line t(sru_length(crypto:strong_rand_mpint(N,-1,0)) =< N),
+ ?line t(sru_length(crypto:strong_rand_mpint(N,0,0)) =:= N),
+ ?line t(crypto:erlint(crypto:strong_rand_mpint(N,0,1)) band 1 =:= 1),
+ ?line t(crypto:erlint(crypto:strong_rand_mpint(N,1,0)) bsr (N - 2) =:= 2#11),
+ ?line strong_rand_aux_test(N-1).
+
+sru_length(Mpint) ->
+ I = crypto:erlint(Mpint),
+ length(erlang:integer_to_list(I, 2)).
+
+%%
+%%
+%%
+%%
+rsa_verify_test(doc) ->
+ "rsa_verify testing (A ^ M % P with bignums)";
+rsa_verify_test(suite) ->
+ [];
+rsa_verify_test(Config) when is_list(Config) ->
+ ?line H = <<178,28,54,104,36,80,144,66,140,201,135,17,36,97,114,124,
+ 194,164,172,147>>,
+ ?line SigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70,
+ 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241,
+ 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23,
+ 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76,
+ 115,34,107,227,151,47,80,185,143,85,202,55,245,163,226,26,
+ 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180,
+ 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14,
+ 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>,
+ ?line BadSigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70,
+ 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241,
+ 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23,
+ 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76,
+ 115,107,34,227,151,47,80,185,143,85,202,55,245,163,226,26,
+ 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180,
+ 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14,
+ 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>,
+ ?line E = <<35>>,
+ ?line N = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10,
+ 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193,
+ 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6,
+ 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1,
+ 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123,
+ 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50,
+ 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73,
+ 76,89,40,33,147,208,189,76,98,24,61,8,10,110,165,119,165>>,
+ ?line Nbad = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10,
+ 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193,
+ 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6,
+ 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1,
+ 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123,
+ 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50,
+ 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73,
+ 76,89,40,33,147,189,208,76,98,24,61,8,10,110,165,119,165>>,
+ ?line Ebad = <<77>>,
+ ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
+ [sized_binary(E), sized_binary(N)]), true),
+ ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
+ [sized_binary(Ebad), sized_binary(N)]), false),
+ ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
+ [sized_binary(E), sized_binary(Nbad)]), false),
+ ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(BadSigBlob),
+ [sized_binary(E), sized_binary(N)]), false).
+
+%%
+%%
+dsa_verify_test(doc) ->
+ "dsa_verify testing (A ^ M % P with bignums)";
+dsa_verify_test(suite) ->
+ [];
+dsa_verify_test(Config) when is_list(Config) ->
+ ?line Msg = <<48,130,2,245,160,3,2,1,2,2,1,1,48,9,6,7,42,134,72,206,56,4,3,48,
+ 58,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3,85,4,10,19,17,
+ 84,101,115,116,32,67,101,114,116,105,102,105,99,97,116,101,115,49,
+ 15,48,13,6,3,85,4,3,19,6,68,83,65,32,67,65,48,30,23,13,48,49,48,
+ 52,49,57,49,52,53,55,50,48,90,23,13,49,49,48,52,49,57,49,52,53,55,
+ 50,48,90,48,93,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3,
+ 85,4,10,19,17,84,101,115,116,32,67,101,114,116,105,102,105,99,97,
+ 116,101,115,49,50,48,48,6,3,85,4,3,19,41,86,97,108,105,100,32,68,
+ 83,65,32,83,105,103,110,97,116,117,114,101,115,32,69,69,32,67,101,
+ 114,116,105,102,105,99,97,116,101,32,84,101,115,116,52,48,130,1,
+ 182,48,130,1,43,6,7,42,134,72,206,56,4,1,48,130,1,30,2,129,129,0,
+ 228,139,175,64,140,21,215,61,124,238,3,150,18,104,193,32,5,232,23,
+ 202,158,116,101,75,154,84,151,42,120,51,218,165,197,114,234,52,
+ 179,148,104,66,213,27,253,119,240,168,66,158,100,147,144,182,194,
+ 2,49,70,19,122,3,105,204,152,45,86,157,94,35,95,40,191,173,127,15,
+ 208,105,149,98,92,26,7,42,94,140,115,73,126,253,18,34,142,85,229,
+ 86,233,174,114,41,150,135,8,39,215,119,67,240,134,184,9,10,27,20,
+ 165,230,3,230,69,121,77,233,250,83,95,193,9,189,126,197,195,2,21,
+ 0,128,63,228,252,243,76,229,62,203,15,23,10,42,84,108,208,103,108,
+ 13,59,2,129,128,102,212,22,138,32,173,254,209,50,159,165,127,167,
+ 179,208,234,119,63,235,108,162,228,41,216,216,188,33,221,154,247,
+ 204,229,180,119,77,223,236,218,162,140,156,117,18,90,31,254,102,
+ 211,17,194,239,132,67,236,169,136,110,76,186,76,63,53,150,199,103,
+ 252,153,189,15,153,41,19,145,78,216,2,174,254,107,175,80,86,170,
+ 47,30,181,42,200,238,34,71,37,120,107,33,221,20,63,206,240,16,129,
+ 247,150,29,156,65,187,94,68,146,93,46,198,30,184,205,105,200,143,
+ 63,59,62,208,79,162,206,217,3,129,132,0,2,129,128,15,83,40,172,56,
+ 47,61,243,17,97,65,195,61,167,214,122,247,246,1,50,211,33,113,16,
+ 20,213,195,62,77,235,25,162,140,175,158,8,61,65,10,255,204,162,71,
+ 130,122,86,161,163,253,236,178,139,183,57,181,202,160,25,133,130,
+ 155,150,104,168,187,107,186,144,164,225,173,101,182,68,49,210,30,
+ 34,47,83,65,79,250,156,248,47,232,44,67,36,22,126,43,216,100,247,
+ 100,250,240,121,72,29,185,2,109,144,54,204,235,54,15,242,57,171,
+ 125,39,236,247,71,111,221,51,196,126,77,238,36,87,163,107,48,105,
+ 48,29,6,3,85,29,14,4,22,4,20,179,51,215,81,162,4,13,68,251,157,64,
+ 241,18,98,113,176,83,246,105,13,48,31,6,3,85,29,35,4,24,48,22,128,
+ 20,116,21,213,36,28,189,94,101,136,31,225,139,9,126,127,234,25,72,
+ 78,97,48,23,6,3,85,29,32,4,16,48,14,48,12,6,10,96,134,72,1,101,3,
+ 2,1,48,1,48,14,6,3,85,29,15,1,1,255,4,4,3,2,6,192>>,
+
+ ?line SigBlob = <<48,45,2,21,0,140,167,200,210,153,212,64,155,249,33,146,104,243,
+ 39,38,9,115,162,89,24,2,20,76,254,31,128,187,48,128,215,216,
+ 112,198,78,118,160,217,157,180,246,64,234>>,
+ ?line P_p = 157224271412839155721795253728878055347359513988016145491388196653004661857517720927482198111104095793441029858267073789634147217022008635826863307553453131345099940951090826856271796188522037524757740796268675508118348391218066949174594918958269259937813776150149068811425194955973128428675945283593831134219,
+ ?line Q_p = 1181895316321540581845959276009400765315408342791,
+ ?line G_p = 143872196713149000950547166575757355261637863805587906227228163275557375159769599033632918292482002186641475268486598023281100659643528846513898847919251032731261718358900479488287933293278745715922865499005559197328388506945134386346185262919258658109015074718441639029135304654725637911172671711310801418648,
+
+ ?line Key = 12603618348903387232593303690286336220738319446775939686476278478034365380027994899970214309288018488811754534229198764622077544117034174589418477472887827980332636062691833965078594576024299807057520016043084384987871640003684704483975314128362610573625803532737054022545217931847268776098203204571431581966,
+
+ ValidKey = [crypto:mpint(P_p),
+ crypto:mpint(Q_p),
+ crypto:mpint(G_p),
+ crypto:mpint(Key)
+ ],
+
+ ?line m(my_dss_verify(sized_binary(Msg), sized_binary(SigBlob),
+ ValidKey), true),
+
+ BadMsg = one_bit_wrong(Msg),
+ ?line m(my_dss_verify(sized_binary(BadMsg), sized_binary(SigBlob),
+ ValidKey), false),
+ BadSig = one_bit_wrong(SigBlob),
+ ?line m(my_dss_verify(sized_binary(Msg), sized_binary(BadSig),
+ ValidKey), false),
+ SizeErr = size(SigBlob) - 13,
+
+ BadArg = (catch my_dss_verify(sized_binary(Msg), <<SizeErr:32, SigBlob/binary>>,
+ ValidKey)),
+ badarg = case element(1,element(2,BadArg)) of
+ badarg -> badarg;
+ function_clause -> badarg;
+ X -> X
+ end,
+ InValidKey = [crypto:mpint(P_p),
+ crypto:mpint(Q_p),
+ crypto:mpint(G_p),
+ crypto:mpint(Key+17)
+ ],
+
+ ?line m(my_dss_verify(sized_binary(Msg), sized_binary(SigBlob),
+ InValidKey), false).
+
+
+one_bit_wrong(List) when is_list(List) ->
+ lists:map(fun(Bin) -> one_bit_wrong(Bin) end, List);
+one_bit_wrong(Bin) ->
+ Half = size(Bin) div 2,
+ <<First:Half/binary, Byte:8, Last/binary>> = Bin,
+ <<First/binary, (Byte+1):8, Last/binary>>.
+
+
+%%
+%% Sign tests
+
+rsa_sign_test(doc) ->
+ "rsa_sign testing";
+rsa_sign_test(suite) ->
+ [];
+rsa_sign_test(Config) when is_list(Config) ->
+ PubEx = 65537,
+ PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
+ Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
+ Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>,
+
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
+ PubKeyMpint = map_int_to_mpint(PubKey),
+ Sig1 = crypto:rsa_sign(sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig1 = crypto:sign(rsa, sha, Msg, PrivKey),
+ true = crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
+
+ Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig2 = crypto:sign(rsa, md5, Msg, PrivKey),
+ true = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2), PubKeyMpint),
+ true = crypto:verify(rsa, md5, Msg, Sig2, PubKey),
+
+ false = (Sig1 =:= Sig2),
+ false = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ false = crypto:verify(rsa, md5, Msg, Sig1, PubKey),
+ true = crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
+
+ ok.
+map_int_to_mpint(List) ->
+ lists:map(fun(E) -> crypto:mpint(E) end, List).
+
+rsa_sign_hash_test(doc) ->
+ "rsa_sign_hash testing";
+rsa_sign_hash_test(suite) ->
+ [];
+rsa_sign_hash_test(Config) when is_list(Config) ->
+ PubEx = 65537,
+ PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
+ Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
+ Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>,
+
+ PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
+ PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
+ MD5 = crypto:md5(sized_binary(Msg)),
+ SHA = crypto:sha(sized_binary(Msg)),
+ ?line Sig1 = crypto:rsa_sign(sha, {digest,SHA}, PrivKey),
+ ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig1),PubKey), true),
+
+ ?line Sig2 = crypto:rsa_sign(md5, {digest,MD5}, PrivKey),
+ ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig2),PubKey), true),
+
+ ?line m(Sig1 =:= Sig2, false),
+ ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig1),PubKey), false),
+ ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig2),PubKey), false),
+
+ ok.
+
+dsa_sign_test(doc) ->
+ "dsa_sign testing";
+dsa_sign_test(suite) ->
+ [];
+dsa_sign_test(Config) when is_list(Config) ->
+ Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>,
+
+ PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978,
+ PrivKey = _X = 441502407453038284293378221372000880210588566361,
+ ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
+ ParamQ = 1349199015905534965792122312016505075413456283393,
+ ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669,
+
+ Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)],
+ ?line Sig1 = my_dss_sign(sized_binary(Msg), Params ++ [crypto:mpint(PrivKey)]),
+
+ ?line m(my_dss_verify(sized_binary(Msg), Sig1,
+ Params ++ [crypto:mpint(PubKey)]), true),
+
+ ?line m(my_dss_verify(sized_binary(one_bit_wrong(Msg)), Sig1,
+ Params ++ [crypto:mpint(PubKey)]), false),
+
+ ?line m(my_dss_verify(sized_binary(Msg), one_bit_wrong(Sig1),
+ Params ++ [crypto:mpint(PubKey)]), false),
+
+ %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]),
+
+ ok.
+
+dsa_sign_hash_test(doc) ->
+ "dsa_sign_hash testing";
+dsa_sign_hash_test(suite) ->
+ [];
+dsa_sign_hash_test(Config) when is_list(Config) ->
+ Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>,
+ SHA = crypto:sha(sized_binary(Msg)),
+
+ PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978,
+ PrivKey = _X = 441502407453038284293378221372000880210588566361,
+ ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
+ ParamQ = 1349199015905534965792122312016505075413456283393,
+ ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669,
+
+ Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)],
+ ?line Sig1 = crypto:dss_sign(sha, {digest,SHA}, Params ++ [crypto:mpint(PrivKey)]),
+
+ ?line m(crypto:dss_verify(none, SHA, sized_binary(Sig1),
+ Params ++ [crypto:mpint(PubKey)]), true),
+
+ ?line m(crypto:dss_verify(sized_binary(one_bit_wrong(Msg)), sized_binary(Sig1),
+ Params ++ [crypto:mpint(PubKey)]), false),
+
+ ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(one_bit_wrong(Sig1)),
+ Params ++ [crypto:mpint(PubKey)]), false),
+
+ %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]),
+
+ ok.
+
+
+rsa_encrypt_decrypt(doc) ->
+ ["Test rsa_public_encrypt and rsa_private_decrypt functions."];
+rsa_encrypt_decrypt(suite) -> [];
+rsa_encrypt_decrypt(Config) when is_list(Config) ->
+ PubEx = 65537,
+ PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
+ Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
+
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
+
+ Msg = <<"7896345786348 Asldi">>,
+
+ ?line PKCS1 = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
+ ?line PKCS1Dec = rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
+ io:format("PKCS1Dec ~p~n",[PKCS1Dec]),
+ ?line Msg = PKCS1Dec,
+
+ ?line OAEP = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
+ ?line Msg = rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
+
+ <<Msg2Len:32,_/binary>> = crypto:mpint(Mod),
+ Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)),
+ ?line NoPad = rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
+ ?line NoPadDec = rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
+ ?line NoPadDec = Msg2,
+
+ ShouldBeError = (catch rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
+ ?line {'EXIT', {encrypt_failed,_}} = ShouldBeError,
+
+%% ?line SSL = rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
+%% ?line Msg = rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
+
+ ?line PKCS1_2 = rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
+ ?line PKCS1_2Dec = rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
+ io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]),
+ ?line Msg = PKCS1_2Dec,
+
+ ?line PKCS1_3 = rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
+ ?line PKCS1_3Dec = rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
+ io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]),
+ ?line Msg2 = PKCS1_3Dec,
+
+ ?line {'EXIT', {encrypt_failed,_}} =
+ (catch rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
+
+ ok.
+
+rsa_public_encrypt(Msg, Key, Pad) ->
+ C1 = crypto:rsa_public_encrypt(Msg, Key, Pad),
+ C2 = crypto:rsa_public_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ {C1,C2}.
+
+rsa_public_decrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_public_decrypt(Msg, Key, Pad),
+ R = crypto:rsa_public_decrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_encrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_private_encrypt(Msg, Key, Pad),
+ R = crypto:rsa_private_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_decrypt({C1,C2}, Key, Pad) ->
+ R = crypto:rsa_private_decrypt(C1, Key, Pad),
+ R = crypto:rsa_private_decrypt(C2, Key, Pad),
+ R = crypto:rsa_private_decrypt(C1, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ R = crypto:rsa_private_decrypt(C2, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+
+dh(doc) ->
+ ["Test dh (Diffie-Hellman) functions."];
+dh(suite) -> [];
+dh(Config) when is_list(Config) ->
+ Self = self(),
+ GenP = fun() ->
+ %% Gen Param may take arbitrary long time to finish
+ %% That's not a bug in erlang crypto application.
+ ?line DHPs = crypto:dh_generate_parameters(512,2),
+ ?line ok = crypto:dh_check(DHPs),
+ Self ! {param, DHPs}
+ end,
+ Pid = spawn(GenP),
+ receive
+ {param, DHPs} ->
+ timer:sleep(100),
+ io:format("DHP ~p~n", [DHPs]),
+ DHPs_mpint = lists:map(fun(E) -> sized_binary(E) end, DHPs),
+ ?line {Pub1,Priv1} = crypto:generate_key(dh, DHPs),
+ io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]),
+ ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs_mpint),
+ io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]),
+ ?line A = crypto:compute_key(dh, Pub1, unsized_binary(Priv2), DHPs),
+ ?line A = crypto:dh_compute_key(sized_binary(Pub1), Priv2, DHPs_mpint),
+ timer:sleep(100), %% Get another thread see if that triggers problem
+ ?line B = crypto:compute_key(dh, unsized_binary(Pub2), Priv1, DHPs),
+ ?line B = crypto:dh_compute_key(Pub2, sized_binary(Priv1), DHPs_mpint),
+ io:format("A ~p~n",[A]),
+ io:format("B ~p~n",[B]),
+ ?line A = B
+ after 50000 ->
+ io:format("Killing Param generation which took to long ~p~n",[Pid]),
+ exit(Pid, kill)
+ end.
+
+
+ec(doc) ->
+ ["Test ec (Ecliptic Curve) functions."];
+ec(suite) -> [];
+ec(Config) when is_list(Config) ->
+ if_supported(ecdh, fun() -> ec_do() end).
+
+ec_do() ->
+ %% test for a name curve
+ {D2_pub, D2_priv} = crypto:generate_key(ecdh, sect113r2),
+ PrivECDH = [D2_priv, sect113r2],
+ PubECDH = [D2_pub, sect113r2],
+ %%TODO: find a published test case for a EC key
+
+ %% test for a full specified curve and public key,
+ %% taken from csca-germany_013_self_signed_cer.pem
+ PubKey = <<16#04, 16#4a, 16#94, 16#49, 16#81, 16#77, 16#9d, 16#df,
+ 16#1d, 16#a5, 16#e7, 16#c5, 16#27, 16#e2, 16#7d, 16#24,
+ 16#71, 16#a9, 16#28, 16#eb, 16#4d, 16#7b, 16#67, 16#75,
+ 16#ae, 16#09, 16#0a, 16#51, 16#45, 16#19, 16#9b, 16#d4,
+ 16#7e, 16#a0, 16#81, 16#e5, 16#5e, 16#d4, 16#a4, 16#3f,
+ 16#60, 16#7c, 16#6a, 16#50, 16#ee, 16#36, 16#41, 16#8a,
+ 16#87, 16#ff, 16#cd, 16#a6, 16#10, 16#39, 16#ca, 16#95,
+ 16#76, 16#7d, 16#ae, 16#ca, 16#c3, 16#44, 16#3f, 16#e3, 16#2c>>,
+ <<P:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#72, 16#6e, 16#3b, 16#f6, 16#23, 16#d5, 16#26, 16#20,
+ 16#28, 16#20, 16#13, 16#48, 16#1d, 16#1f, 16#6e, 16#53, 16#77>>,
+ <<A:256/integer>> = <<16#7d, 16#5a, 16#09, 16#75, 16#fc, 16#2c, 16#30, 16#57,
+ 16#ee, 16#f6, 16#75, 16#30, 16#41, 16#7a, 16#ff, 16#e7,
+ 16#fb, 16#80, 16#55, 16#c1, 16#26, 16#dc, 16#5c, 16#6c,
+ 16#e9, 16#4a, 16#4b, 16#44, 16#f3, 16#30, 16#b5, 16#d9>>,
+ <<B:256/integer>> = <<16#26, 16#dc, 16#5c, 16#6c, 16#e9, 16#4a, 16#4b, 16#44,
+ 16#f3, 16#30, 16#b5, 16#d9, 16#bb, 16#d7, 16#7c, 16#bf,
+ 16#95, 16#84, 16#16, 16#29, 16#5c, 16#f7, 16#e1, 16#ce,
+ 16#6b, 16#cc, 16#dc, 16#18, 16#ff, 16#8c, 16#07, 16#b6>>,
+ BasePoint = <<16#04, 16#8b, 16#d2, 16#ae, 16#b9, 16#cb, 16#7e, 16#57,
+ 16#cb, 16#2c, 16#4b, 16#48, 16#2f, 16#fc, 16#81, 16#b7,
+ 16#af, 16#b9, 16#de, 16#27, 16#e1, 16#e3, 16#bd, 16#23,
+ 16#c2, 16#3a, 16#44, 16#53, 16#bd, 16#9a, 16#ce, 16#32,
+ 16#62, 16#54, 16#7e, 16#f8, 16#35, 16#c3, 16#da, 16#c4,
+ 16#fd, 16#97, 16#f8, 16#46, 16#1a, 16#14, 16#61, 16#1d,
+ 16#c9, 16#c2, 16#77, 16#45, 16#13, 16#2d, 16#ed, 16#8e,
+ 16#54, 16#5c, 16#1d, 16#54, 16#c7, 16#2f, 16#04, 16#69, 16#97>>,
+ <<Order:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#71, 16#8c, 16#39, 16#7a, 16#a3, 16#b5, 16#61, 16#a6,
+ 16#f7, 16#90, 16#1e, 16#0e, 16#82, 16#97, 16#48, 16#56, 16#a7>>,
+ CoFactor = 1,
+ Curve = {{prime_field,P},{A,B,none},BasePoint, Order,CoFactor},
+
+ Msg = <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>,
+ Sign = crypto:sign(ecdsa, sha, Msg, PrivECDH),
+ ?line true = crypto:verify(ecdsa, sha, Msg, Sign, PubECDH),
+ ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, PubECDH),
+
+ ok.
+
+srp3(doc) ->
+ ["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp3(suite) -> [];
+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_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
+
+srp6(doc) ->
+ ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+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_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
+
+srp6a(doc) ->
+ ["SRP-6a test vectors from RFC5054."];
+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_pow(Generator, UserPassHash, Prime),
+
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
+
+%%
+%%
+exor_test(doc) ->
+ ["Test the exor function."];
+exor_test(suite) ->
+ [];
+exor_test(Config) when is_list(Config) ->
+ B = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>,
+ Z1 = zero_bin(B),
+ Z1 = crypto:exor(B, B),
+ B1 = crypto:rand_bytes(100),
+ B2 = crypto:rand_bytes(100),
+ Z2 = zero_bin(B1),
+ Z2 = crypto:exor(B1, B1),
+ Z2 = crypto:exor(B2, B2),
+ R = xor_bytes(B1, B2),
+ R = crypto:exor(B1, B2),
+ ok.
+
+%%
+%%
+rc4_test(doc) ->
+ ["Test rc4 encryption ."];
+rc4_test(suite) ->
+ [];
+rc4_test(Config) when is_list(Config) ->
+ CT1 = <<"Yo baby yo">>,
+ R1 = <<118,122,68,110,157,166,141,212,139,39>>,
+ K = "apaapa",
+ R1 = crypto:rc4_encrypt(K, CT1),
+ CT1 = crypto:rc4_encrypt(K, R1),
+ CT2 = lists:seq(0, 255),
+ R2 = crypto:rc4_encrypt(K, CT2),
+ CT2 = binary_to_list(crypto:rc4_encrypt(K, R2)),
+ ok.
+
+rc4_stream_test(doc) ->
+ ["Test rc4 stream encryption ."];
+rc4_stream_test(suite) ->
+ [];
+rc4_stream_test(Config) when is_list(Config) ->
+ CT1 = <<"Yo ">>,
+ CT2 = <<"baby yo">>,
+ K = "apaapa",
+ State0 = crypto:rc4_set_key(K),
+ {State1, R1} = crypto:rc4_encrypt_with_state(State0, CT1),
+ {_State2, R2} = crypto:rc4_encrypt_with_state(State1, CT2),
+ R = list_to_binary([R1, R2]),
+ <<118,122,68,110,157,166,141,212,139,39>> = R,
+ ok.
+
+blowfish_cfb64(doc) -> ["Test Blowfish encrypt/decrypt."];
+blowfish_cfb64(suite) -> [];
+blowfish_cfb64(Config) when is_list(Config) ->
+ Key = <<1,35,69,103,137,171,205,239,240,225,210,195,180,165,150,135>>,
+
+ IVec = <<254,220,186,152,118,84,50,16>>,
+ Plain = <<"7654321 Now is the time for ">>,
+ Enc = <<231,50,20,162,130,33,57,202,242,110,207,109,46,185,231,110,61,163,222,4,209,81,114,0,81,157,87,166>>,
+
+ Enc = crypto:blowfish_cfb64_encrypt(Key, IVec, Plain),
+ Plain = crypto:blowfish_cfb64_decrypt(Key, IVec, Enc),
+
+ Key2 = <<"A2B4C">>,
+ IVec2 = <<"12345678">>,
+ Plain2 = <<"badger at my table....!">>,
+ Enc2 = <<173,76,128,155,70,81,79,228,4,162,188,92,119,53,144,89,93,236,28,164,176,16,138>>,
+
+ Enc2 = crypto:blowfish_cfb64_encrypt(Key2, IVec2, Plain2),
+ Plain2 = crypto:blowfish_cfb64_decrypt(Key2, IVec2, Enc2).
+
+
+smp(doc) -> "Check concurrent access to crypto driver";
+smp(suite) -> [];
+smp(Config) ->
+ case erlang:system_info(smp_support) of
+ true ->
+ NumOfProcs = erlang:system_info(schedulers),
+ io:format("smp starting ~p workers\n",[NumOfProcs]),
+ Seeds = [random:uniform(9999) || _ <- lists:seq(1,NumOfProcs)],
+ Parent = self(),
+ Pids = [spawn_link(fun()-> worker(Seed,Config,Parent) end)
+ || Seed <- Seeds],
+ wait_pids(Pids);
+
+ false ->
+ {skipped,"No smp support"}
+ end.
+
+worker(Seed, Config, Parent) ->
+ io:format("smp worker ~p, seed=~p~n",[self(),Seed]),
+ random:seed(Seed,Seed,Seed),
+ worker_loop(100, Config),
+ %%io:format("worker ~p done\n",[self()]),
+ Parent ! self().
+
+worker_loop(0, _) ->
+ ok;
+worker_loop(N, Config) ->
+ Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc,
+ 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_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]),
+ ?MODULE:F(Config),
+ worker_loop(N-1,Config).
+
+wait_pids([]) ->
+ ok;
+wait_pids(Pids) ->
+ receive
+ Pid ->
+ ?line true = lists:member(Pid,Pids),
+ Others = lists:delete(Pid,Pids),
+ io:format("wait_pid got ~p, still waiting for ~p\n",[Pid,Others]),
+ wait_pids(Others)
+ end.
+
+%%
+%% Help functions
+%%
+
+% match
+m(X, X) ->
+ ?line true.
+t(true) ->
+ true.
+
+% hexstr2bin
+hexstr2bin(S) ->
+ list_to_binary(hexstr2list(S)).
+
+hexstr2list([X,Y|T]) ->
+ [mkint(X)*16 + mkint(Y) | hexstr2list(T)];
+hexstr2list([]) ->
+ [].
+
+mkint(C) when $0 =< C, C =< $9 ->
+ C - $0;
+mkint(C) when $A =< C, C =< $F ->
+ C - $A + 10;
+mkint(C) when $a =< C, C =< $f ->
+ C - $a + 10.
+
+%% mod_exp in erlang (copied from jungerl's ssh_math.erl)
+ipow(A, B, M) when M > 0, B >= 0 ->
+ if A == 1 ->
+ 1;
+ true ->
+ ipow(A, B, M, 1)
+ end.
+
+ipow(A, 1, M, Prod) ->
+ (A*Prod) rem M;
+ipow(_A, 0, _M, Prod) ->
+ Prod;
+ipow(A, B, M, Prod) ->
+ B1 = B bsr 1,
+ A1 = (A*A) rem M,
+ if B - B1 == B1 ->
+ ipow(A1, B1, M, Prod);
+ true ->
+ ipow(A1, B1, M, (A*Prod) rem M)
+ end.
+
+%%
+%% Invert an element X mod P
+%% Calculated as {1, {A,B}} = egcd(X,P),
+%% 1 == P*A + X*B == X*B (mod P) i.e B is the inverse element
+%%
+%% X > 0, P > 0, X < P (P should be prime)
+%%
+%% invert(X,P) when X > 0, P > 0, X < P ->
+%% I = inv(X,P,1,0),
+%% if
+%% I < 0 -> P + I;
+%% true -> I
+%% end.
+
+%% inv(0,_,_,Q) -> Q;
+%% inv(X,P,R1,Q1) ->
+%% D = P div X,
+%% inv(P rem X, X, Q1 - D*R1, R1).
+
+sized_binary(Binary) when is_binary(Binary) ->
+ <<(size(Binary)):32/integer, Binary/binary>>;
+sized_binary(List) ->
+ sized_binary(list_to_binary(List)).
+
+unsized_binary(<<Sz:32/integer, Binary:Sz/binary>>) ->
+ Binary.
+
+xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) ->
+ L1 = binary_to_list(Bin1),
+ L2 = binary_to_list(Bin2),
+ list_to_binary(xor_bytes(L1, L2));
+xor_bytes(L1, L2) ->
+ xor_bytes(L1, L2, []).
+
+xor_bytes([], [], Acc) ->
+ lists:reverse(Acc);
+xor_bytes([N1 | Tl1], [N2 | Tl2], Acc) ->
+ xor_bytes(Tl1, Tl2, [N1 bxor N2 | Acc]).
+
+zero_bin(N) when is_integer(N) ->
+ N8 = N * 8,
+ <<0:N8/integer>>;
+zero_bin(B) when is_binary(B) ->
+ zero_bin(size(B)).
+
+my_dss_verify(Data,[Sign|Tail],Key) ->
+ Res = my_dss_verify(Data,sized_binary(Sign),Key),
+ case Tail of
+ [] -> Res;
+ _ -> ?line Res = my_dss_verify(Data,Tail,Key)
+ end;
+my_dss_verify(Data,Sign,Key) ->
+ ?line Res = crypto:dss_verify(Data, Sign, Key),
+ ?line Res = crypto:dss_verify(sha, Data, Sign, Key),
+ ?line <<_:32,Raw/binary>> = Data,
+ ?line Res = crypto:dss_verify(none, crypto:sha(Raw), Sign, Key),
+ Res.
+
+my_dss_sign(Data,Key) ->
+ ?line S1 = crypto:dss_sign(Data, Key),
+ ?line S2 = crypto:dss_sign(sha, Data, Key),
+ ?line <<_:32,Raw/binary>> = Data,
+ ?line S3 = crypto:dss_sign(none, crypto:sha(Raw), Key),
+ [S1,S2,S3].
+
+openssl_version() ->
+ case crypto:info_lib() of
+ [{<<"OpenSSL">>,LibVer,_}] when is_integer(LibVer) ->
+ LibVer;
+ _ ->
+ undefined
+ end.
+
+if_supported(Algorithm, Fun) ->
+ case lists:member(Algorithm, lists:append([Algo || {_, Algo} <- crypto:supports()])) of
+ true ->
+ Fun();
+ _ ->
+ {skipped, io:format("~s not spupported", [Algorithm])}
+ end.
diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl
index c21ad486e8..d8285d7288 100644
--- a/lib/debugger/src/dbg_debugged.erl
+++ b/lib/debugger/src/dbg_debugged.erl
@@ -19,8 +19,6 @@
-module(dbg_debugged).
%% External exports
-%% Avoid warning for local function demonitor/1 clashing with autoimported BIF.
--compile({no_auto_import,[demonitor/1]}).
-export([eval/3]).
%%====================================================================
@@ -47,7 +45,7 @@ msg_loop(Meta, Mref, SaveStacktrace) ->
%% Evaluated function has returned a value
{sys, Meta, {ready, Val}} ->
- demonitor(Mref),
+ erlang:demonitor(Mref, [flush]),
%% Restore original stacktrace and return the value
try erlang:raise(throw, stack, SaveStacktrace)
@@ -63,7 +61,7 @@ msg_loop(Meta, Mref, SaveStacktrace) ->
%% Evaluated function raised an (uncaught) exception
{sys, Meta, {exception,{Class,Reason,Stacktrace}}} ->
- demonitor(Mref),
+ erlang:demonitor(Mref, [flush]),
%% ...raise the same exception
erlang:error(erlang:raise(Class, Reason, Stacktrace),
@@ -107,14 +105,6 @@ reply({eval,Expr,Bs}) ->
%% Bindings is an orddict (sort them)
erl_eval:expr(Expr, lists:sort(Bs)). % {value, Value, Bs2}
-%% Demonitor and delete message from inbox
-%%
-demonitor(Mref) ->
- erlang:demonitor(Mref),
- receive {'DOWN',Mref,_,_,_} -> ok
- after 0 -> ok
- end.
-
%% Fix stacktrace - keep all above call to this module.
%%
stacktrace_f([]) -> [];
diff --git a/lib/debugger/src/dbg_istk.erl b/lib/debugger/src/dbg_istk.erl
index c6922a80e4..ced42a5f9f 100644
--- a/lib/debugger/src/dbg_istk.erl
+++ b/lib/debugger/src/dbg_istk.erl
@@ -78,7 +78,7 @@ push(Bs, #ieval{level=Le,module=Mod,function=Name,
pop() ->
case get(trace_stack) of
false -> ignore;
- _ -> % all ¦ no_tail
+ _ -> % all | no_tail
case get(?STACK) of
[_Entry|Entries] ->
put(?STACK, Entries);
diff --git a/lib/dialyzer/src/dialyzer_gui.erl b/lib/dialyzer/src/dialyzer_gui.erl
index ac9844c22c..97e5752577 100644
--- a/lib/dialyzer/src/dialyzer_gui.erl
+++ b/lib/dialyzer/src/dialyzer_gui.erl
@@ -2,7 +2,7 @@
%%------------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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
@@ -1331,7 +1331,8 @@ build_analysis_record(#gui_state{mode = Mode, menu = Menu, options = Options,
#analysis{defines = Options#options.defines,
include_dirs = Options#options.include_dirs,
plt = InitPlt,
- start_from = StartFrom}.
+ start_from = StartFrom,
+ solvers = Options#options.solvers}.
get_anal_files(#gui_state{chosen_box = ChosenBox}, StartFrom) ->
Files = gs:read(ChosenBox, items),
diff --git a/lib/dialyzer/src/dialyzer_gui_wx.erl b/lib/dialyzer/src/dialyzer_gui_wx.erl
index c6f7c56227..08f31c1e13 100644
--- a/lib/dialyzer/src/dialyzer_gui_wx.erl
+++ b/lib/dialyzer/src/dialyzer_gui_wx.erl
@@ -2,7 +2,7 @@
%%------------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
+%% 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
@@ -810,7 +810,8 @@ build_analysis_record(#gui_state{mode = Mode, menu = Menu, options = Options,
#analysis{defines = Options#options.defines,
include_dirs = Options#options.include_dirs,
plt = InitPlt,
- start_from = StartFrom}.
+ start_from = StartFrom,
+ solvers = Options#options.solvers}.
get_anal_files(#gui_state{files_to_analyze = Files}, StartFrom) ->
FilteredMods =
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl
index 8ec84d798f..7eb4c6ec97 100644
--- a/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl
@@ -1,3 +1,5 @@
+%%% -*- coding: utf-8 -*-
+%%%
%%% Dialyzer was giving a warning with this input because of a bug in the
%%% substitution of remote types in specs. Remote types in the first element of
%%% a tuple would not update the tuple's tag set and we could end up with a
diff --git a/lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl b/lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl
index 5503f39412..e6256e5a53 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl
@@ -69,8 +69,8 @@ test(TargetId, [Date | DateTail], Key, IVT, IVF) ->
{ok, message_from_server(), binary(), binary()}.
culprit(Message, Key, IVecToServer, IVecFromServer) ->
{Packet, NewIVecToServer} = message_to_packet(Message, Key, IVecToServer),
- Message = crypto:aes_cbc_128_decrypt(Key, IVecFromServer, Packet),
- NewIVecFromServer = crypto:aes_cbc_ivec(Packet),
+ Message = crypto:block_decrypt(aes_cbc128, Key, IVecFromServer, Packet),
+ NewIVecFromServer = crypto:next_iv(aes_cbc, Packet),
ParsedMessage = parse_message(Message),
{ok, ParsedMessage, NewIVecToServer, NewIVecFromServer}.
@@ -185,9 +185,9 @@ parse_audio_output_info(<<Output:?DWORD, BitMap:?BITMAP1, Rest/binary>>) ->
-spec message_to_packet(binary(), binary(), binary()) -> {binary(), binary()}.
message_to_packet(Message, Key, IVec) ->
PaddedMessage = pad_pkcs5(Message),
- Packet = crypto:aes_cbc_128_encrypt(Key, IVec, PaddedMessage),
+ Packet = crypto:block_encrypt(aes_cbc128, Key, IVec, PaddedMessage),
TotalSize = byte_size(Packet),
- NewIVec = crypto:aes_cbc_ivec(Packet),
+ NewIVec = crypto:next_iv(aes_cbc, Packet),
{<<TotalSize:?WORD, Packet/binary>>, NewIVec}.
-spec pad_pkcs5(binary()) -> binary().
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index df10c33268..c0cf418f06 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -230,7 +230,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
# Can't $(INSTALL_DIR) more than one directory at a time on Solaris.
release_spec: opt
- for d in bin ebin include src/dict; do \
+ for d in bin ebin examples include src/dict; do \
$(INSTALL_DIR) "$(RELSYSDIR)/$$d"; \
done
$(INSTALL_SCRIPT) $(BINS:%=../bin/%) "$(RELSYSDIR)/bin"
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 3ab86bb340..8f1f231b82 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -830,7 +830,8 @@ int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
error:
EI_TRACE_ERR0("ei_accept","<- ACCEPT failed");
- closesocket(fd);
+ if (fd>=0)
+ closesocket(fd);
return ERL_ERROR;
} /* ei_accept */
diff --git a/lib/et/doc/src/et_desc.xmlsrc b/lib/et/doc/src/et_desc.xmlsrc
index c02517ae01..36274f6316 100644
--- a/lib/et/doc/src/et_desc.xmlsrc
+++ b/lib/et/doc/src/et_desc.xmlsrc
@@ -150,7 +150,7 @@
NewEvent = #event{}]]></code>
<p>The interface of the filter function is the same as the the
- filter functions for the good old <c>lists:zf/2</c>. If the filter
+ filter functions for the good old <c>lists:filtermap/2</c>. If the filter
returns <c>false</c> it means that the trace data should silently
be dropped. <c>true</c> means that the trace data data already is
an <c>Event Record</c> and that it should be kept as it is.
diff --git a/lib/et/src/et_collector.erl b/lib/et/src/et_collector.erl
index a63d15fb4c..ce8cf6d4e0 100644
--- a/lib/et/src/et_collector.erl
+++ b/lib/et/src/et_collector.erl
@@ -654,13 +654,8 @@ start_trace_client(CollectorPid, Type, FileName) when Type =:= file ->
Ref = erlang:monitor(process, Pid),
receive
WaitFor ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, _, _, _} ->
- file_loaded
- after 0 ->
- file_loaded
- end;
+ erlang:demonitor(Ref, [flush]),
+ file_loaded;
{'DOWN', Ref, _, _, Reason} ->
exit(Reason)
end;
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
index fff854a5f8..4b321fbce7 100644
--- a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
+++ b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
@@ -135,8 +135,8 @@ public class Environment {
if (connection == null)
connection = self.connect(peer);
- clientP = new com.ericsson.otp.erlang.OtpErlangPid(self); /* This is not perfect */
- send_ref = new com.ericsson.otp.erlang.OtpErlangRef(self);
+ clientP = self.createPid(); /* This is not perfect */
+ send_ref = self.createRef();
}
diff --git a/lib/ic/src/icparse.yrl b/lib/ic/src/icparse.yrl
index d0dd6cde4c..b0286d57f4 100644
--- a/lib/ic/src/icparse.yrl
+++ b/lib/ic/src/icparse.yrl
@@ -230,6 +230,9 @@ Terminals
Rootsymbol '<specification>'.
+Expect 9.
+
+
%%------------------------------------------------------------
%% Clauses
%%
diff --git a/lib/inets/src/http_server/httpd_manager.erl b/lib/inets/src/http_server/httpd_manager.erl
index 672a70a394..c83d06a158 100644
--- a/lib/inets/src/http_server/httpd_manager.erl
+++ b/lib/inets/src/http_server/httpd_manager.erl
@@ -691,11 +691,11 @@ handle_unblock(S, FromA) ->
handle_unblock(S, _FromA, unblocked) ->
{ok,S};
handle_unblock(S, FromA, _AdminState) ->
- stop_block_tmr(S#state.blocking_tmr),
case S#state.blocking_tmr of
- {_Tmr,FromB,Ref} ->
+ {Tmr,FromB,Ref} ->
%% Another process is trying to unblock
%% Inform the blocker
+ stop_block_tmr(Tmr),
FromB ! {block_reply, {error,{unblocked,FromA}},Ref};
_ ->
ok
diff --git a/lib/inets/test/erl_make_certs.erl b/lib/inets/test/erl_make_certs.erl
index 5b92e551a5..22dc951ac1 100644
--- a/lib/inets/test/erl_make_certs.erl
+++ b/lib/inets/test/erl_make_certs.erl
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -277,7 +296,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -298,13 +324,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -349,24 +386,37 @@ gen_dsa2(LSize, NSize) ->
X0 = prime(LSize),
P0 = prime((LSize div 2) +1),
- %% Choose L-bit prime modulus P such that p–1 is a multiple of q.
+ %% Choose L-bit prime modulus P such that p-1 is a multiple of q.
case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
error ->
gen_dsa2(LSize, NSize);
P ->
- G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
- %% such that This may be done by setting g = h^(p–1)/q mod p, commonly h=2 is used.
+ G = crypto:mod_pow(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
X = prime(20), %% Choose x by some random method, where 0 < x < q.
- Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
+ Y = crypto:mod_pow(G, X, P), %% Calculate y = g^x mod p.
- #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ #'DSAPrivateKey'{version=0, p = P, q = Q,
+ g = crypto:bytes_to_integer(G), y = crypto:bytes_to_integer(Y), x = X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+gen_ec2(CurveId) ->
+ {PubKey, PrivKey} = crypto:generate_key(ecdh, CurveId),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = binary_to_list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
- case is_prime(crypto:mpint(P), 50) of
+ case is_prime(P, 50) of
true -> P;
false -> dsa_search(T+1, P0, Q, Iter-1)
end;
@@ -377,38 +427,40 @@ dsa_search(_,_,_,_) ->
%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime(ByteSize) ->
Rand = odd_rand(ByteSize),
- crypto:erlint(prime_odd(Rand, 0)).
+ prime_odd(Rand, 0).
prime_odd(Rand, N) ->
case is_prime(Rand, 50) of
true ->
Rand;
false ->
- NotPrime = crypto:erlint(Rand),
- prime_odd(crypto:mpint(NotPrime+2), N+1)
+ prime_odd(Rand+2, N+1)
end.
%% see http://en.wikipedia.org/wiki/Fermat_primality_test
is_prime(_, 0) -> true;
is_prime(Candidate, Test) ->
- CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
- case crypto:mod_exp(CoPrime, Candidate, Candidate) of
- CoPrime -> is_prime(Candidate, Test-1);
- _ -> false
- end.
+ CoPrime = odd_rand(10000, Candidate),
+ Result = crypto:mod_pow(CoPrime, Candidate, Candidate) ,
+ is_prime(CoPrime, crypto:bytes_to_integer(Result), Candidate, Test).
+
+is_prime(CoPrime, CoPrime, Candidate, Test) ->
+ is_prime(Candidate, Test-1);
+is_prime(_,_,_,_) ->
+ false.
odd_rand(Size) ->
Min = 1 bsl (Size*8-1),
Max = (1 bsl (Size*8))-1,
- odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+ odd_rand(Min, Max).
odd_rand(Min,Max) ->
- Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
- BitSkip = (Sz+4)*8-1,
- case Rand of
- Odd = <<_:BitSkip, 1:1>> -> Odd;
- Even = <<_:BitSkip, 0:1>> ->
- crypto:mpint(crypto:erlint(Even)+1)
+ Rand = crypto:rand_uniform(Min,Max),
+ case Rand rem 2 of
+ 0 ->
+ Rand + 1;
+ _ ->
+ Rand
end.
extended_gcd(A, B) ->
@@ -427,3 +479,4 @@ pem_to_der(File) ->
der_to_pem(File, Entries) ->
PemBin = public_key:pem_encode(Entries),
file:write_file(File, PemBin).
+
diff --git a/lib/jinterface/test/jinterface_SUITE.erl b/lib/jinterface/test/jinterface_SUITE.erl
index b438da12d0..de8d611efc 100644
--- a/lib/jinterface/test/jinterface_SUITE.erl
+++ b/lib/jinterface/test/jinterface_SUITE.erl
@@ -180,7 +180,7 @@ init_per_testcase(Case, _Config)
Case =:= kill_mbox_from_erlang ->
{skip, "Not yet implemented"};
init_per_testcase(_Case,Config) ->
- Dog = ?t:timetrap({seconds,10}),
+ Dog = ?t:timetrap({seconds,30}),
[{watch_dog,Dog}|Config].
end_per_testcase(_Case,Config) ->
@@ -188,6 +188,7 @@ end_per_testcase(_Case,Config) ->
undefined -> ok;
Pid -> exit(Pid,kill)
end,
+ jitu:kill_all_jnodes(),
?t:timetrap_cancel(?config(watch_dog,Config)),
ok.
diff --git a/lib/jinterface/test/jitu.erl b/lib/jinterface/test/jitu.erl
index 0e1af0ff22..a029c063bc 100644
--- a/lib/jinterface/test/jitu.erl
+++ b/lib/jinterface/test/jitu.erl
@@ -27,7 +27,10 @@
java/4,
java/5,
init_all/1,
- finish_all/1]).
+ finish_all/1,
+ kill_all_jnodes/0]).
+
+-include("ct.hrl").
%%
%% Lots of stuff here are originating from java_client_erl_server_SUITE.erl
@@ -51,10 +54,33 @@ java(Java, Dir, Class, Args, Props) ->
init_all(Config) when is_list(Config) ->
case find_executable(["java"]) of
false -> {skip,"Found no Java VM"};
- Path -> [{java,Path}|Config]
+ Path ->
+ Pid = spawn(fun() ->
+ ets:new(jitu_tab,[set,named_table,public]),
+ receive stop -> ets:delete(jitu_tab) end
+ end),
+ [{java,Path},{tab_proc,Pid}|Config]
end.
-finish_all(Config) -> Config.
+finish_all(Config) ->
+ kill_all_jnodes(),
+ ?config(tab_proc,Config) ! stop,
+ Config.
+
+kill_all_jnodes() ->
+ Jnodes = ets:tab2list(jitu_tab),
+ [begin
+% ct:pal("Killing OsPid=~w started with ~p",[OsPid,_Cmd]),
+ kill_os_process(os:type(),integer_to_list(OsPid))
+ end || {OsPid,_Cmd} <- Jnodes],
+ ets:delete_all_objects(jitu_tab),
+ ok.
+
+kill_os_process({win32,_},OsPid) ->
+ os:cmd("taskkill /PID " ++ OsPid);
+kill_os_process(_,OsPid) ->
+ os:cmd("kill " ++ OsPid).
+
%%
%% Internal stuff...
@@ -110,6 +136,12 @@ cmd(Cmd) ->
io:format("cmd: ~s~n", [Cmd]),
case catch open_port({spawn,Cmd}, PortOpts) of
Port when is_port(Port) ->
+ case erlang:port_info(Port,os_pid) of
+ {os_pid,OsPid} ->
+ ets:insert(jitu_tab,{OsPid,Cmd});
+ _ ->
+ ok
+ end,
Result = cmd_loop(Port, []),
io:format("cmd res: ~w~n", [Result]),
case Result of
diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
index 63c78ebdaa..f1493a3cc9 100644
--- a/lib/jinterface/test/nc_SUITE.erl
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -105,12 +105,13 @@ end_per_suite(Config) ->
init_per_testcase(Case, Config) ->
T = case atom_to_list(Case) of
"unicode"++_ -> 240;
- _ -> 30
+ _ -> 120
end,
WatchDog = test_server:timetrap(test_server:seconds(T)),
[{watchdog, WatchDog}| Config].
end_per_testcase(_Case, Config) ->
+ jitu:kill_all_jnodes(),
WatchDog = ?config(watchdog, Config),
test_server:timetrap_cancel(WatchDog).
@@ -695,15 +696,18 @@ run_server(Server, Config, Action, ExtraArgs) ->
true = register(Name, self()),
JName = make_name(),
spawn_link(fun () ->
+ %% Setting max memory to 256. This is due to
+ %% echo_server sometimes failing with
+ %% OutOfMemoryException one some test machines.
ok = jitu:java(?config(java, Config),
?config(data_dir, Config),
atom_to_list(Server),
[JName,
erlang:get_cookie(),
node(),
- Name]++ExtraArgs
- ),
- %,"-DOtpConnection.trace=3"),
+ Name]++ExtraArgs,
+ " -Xmx256m"),
+ %% " -Xmx256m -DOtpConnection.trace=3"),
Name ! {done, JName}
end),
receive
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 541500a300..7cd98914d1 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -559,7 +559,7 @@ fe80::204:acff:fe17:bf38
<c>[Byte1,Byte2|Binary]</c>.</p>
</item>
- <tag><c>{high_msgq_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <tag><c>{high_msgq_watermark, Size}</c></tag>
<item>
<p>The socket message queue will be set into a busy
state when the amount of data queued on the message
@@ -674,7 +674,7 @@ fe80::204:acff:fe17:bf38
the flushing time-out in seconds.</p>
</item>
- <tag><c>{low_msgq_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <tag><c>{low_msgq_watermark, Size}</c></tag>
<item>
<p>If the socket message queue is in a busy state, the
socket message queue will be set in a not busy state when
diff --git a/lib/kernel/src/application_master.erl b/lib/kernel/src/application_master.erl
index 679fefaed9..34a3efcaf2 100644
--- a/lib/kernel/src/application_master.erl
+++ b/lib/kernel/src/application_master.erl
@@ -76,13 +76,8 @@ call(AppMaster, Req) ->
{'DOWN', Ref, process, _, _Info} ->
ok;
{Tag, Res} ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, process, _, _Info} ->
- Res
- after 0 ->
- Res
- end
+ erlang:demonitor(Ref, [flush]),
+ Res
end.
%%%-----------------------------------------------------------------
diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl
index 0c5af2857e..c238eff12f 100644
--- a/lib/kernel/src/disk_log.erl
+++ b/lib/kernel/src/disk_log.erl
@@ -1914,13 +1914,8 @@ multi_req(Msg, Pids) ->
{'DOWN', Ref, process, Pid, _Info} ->
Reply;
{disk_log, Pid, _Reply} ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, process, Pid, _Reason} ->
- ok
- after 0 ->
- ok
- end
+ erlang:demonitor(Ref, [flush]),
+ ok
end
end, {error, nonode}, Refs).
@@ -1965,13 +1960,8 @@ monitor_request(Pid, Req) ->
{error, no_such_log};
{disk_log, Pid, Reply} when not is_tuple(Reply) orelse
element(2, Reply) =/= disk_log_stopped ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, process, Pid, _Reason} ->
- Reply
- after 0 ->
- Reply
- end
+ erlang:demonitor(Ref, [flush]),
+ Reply
end.
req2(Pid, R) ->
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index a4c56b346f..36289053eb 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -480,8 +480,7 @@ open(Item, Mode) ->
Reason :: posix() | badarg | terminated.
close(File) when is_pid(File) ->
- R = file_request(File, close),
- case wait_file_reply(File, R) of
+ case file_request(File, close) of
{error, terminated} ->
ok;
Other ->
@@ -503,8 +502,7 @@ close(_) ->
Reason :: posix() | badarg.
advise(File, Offset, Length, Advise) when is_pid(File) ->
- R = file_request(File, {advise, Offset, Length, Advise}),
- wait_file_reply(File, R);
+ file_request(File, {advise, Offset, Length, Advise});
advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
Module:advise(Handle, Offset, Length, Advise);
advise(_, _, _, _) ->
@@ -517,8 +515,7 @@ advise(_, _, _, _) ->
Length :: non_neg_integer().
allocate(File, Offset, Length) when is_pid(File) ->
- R = file_request(File, {allocate, Offset, Length}),
- wait_file_reply(File, R);
+ file_request(File, {allocate, Offset, Length});
allocate(#file_descriptor{module = Module} = Handle, Offset, Length) ->
Module:allocate(Handle, Offset, Length).
@@ -601,8 +598,7 @@ pread_int(_, _, _) ->
Reason :: posix() | badarg | terminated.
pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 ->
- R = file_request(File, {pread, At, Sz}),
- wait_file_reply(File, R);
+ file_request(File, {pread, At, Sz});
pread(#file_descriptor{module = Module} = Handle, Offs, Sz)
when is_integer(Sz), Sz >= 0 ->
Module:pread(Handle, Offs, Sz);
@@ -658,8 +654,7 @@ pwrite_int(_, _, _) ->
Reason :: posix() | badarg | terminated.
pwrite(File, At, Bytes) when is_pid(File) ->
- R = file_request(File, {pwrite, At, Bytes}),
- wait_file_reply(File, R);
+ file_request(File, {pwrite, At, Bytes});
pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) ->
Module:pwrite(Handle, Offs, Bytes);
pwrite(_, _, _) ->
@@ -670,8 +665,7 @@ pwrite(_, _, _) ->
Reason :: posix() | badarg | terminated.
datasync(File) when is_pid(File) ->
- R = file_request(File, datasync),
- wait_file_reply(File, R);
+ file_request(File, datasync);
datasync(#file_descriptor{module = Module} = Handle) ->
Module:datasync(Handle);
datasync(_) ->
@@ -682,8 +676,7 @@ datasync(_) ->
Reason :: posix() | badarg | terminated.
sync(File) when is_pid(File) ->
- R = file_request(File, sync),
- wait_file_reply(File, R);
+ file_request(File, sync);
sync(#file_descriptor{module = Module} = Handle) ->
Module:sync(Handle);
sync(_) ->
@@ -696,8 +689,7 @@ sync(_) ->
Reason :: posix() | badarg | terminated.
position(File, At) when is_pid(File) ->
- R = file_request(File, {position,At}),
- wait_file_reply(File, R);
+ file_request(File, {position,At});
position(#file_descriptor{module = Module} = Handle, At) ->
Module:position(Handle, At);
position(_, _) ->
@@ -708,8 +700,7 @@ position(_, _) ->
Reason :: posix() | badarg | terminated.
truncate(File) when is_pid(File) ->
- R = file_request(File, truncate),
- wait_file_reply(File, R);
+ file_request(File, truncate);
truncate(#file_descriptor{module = Module} = Handle) ->
Module:truncate(Handle);
truncate(_) ->
@@ -1497,25 +1488,19 @@ check_args([]) ->
ok.
%%-----------------------------------------------------------------
-%% Functions for communicating with a file io server.
+%% Function for communicating with a file io server.
%% The messages sent have the following formats:
%%
%% {file_request,From,ReplyAs,Request}
%% {file_reply,ReplyAs,Reply}
file_request(Io, Request) ->
- R = erlang:monitor(process, Io),
- Io ! {file_request,self(),Io,Request},
- R.
-
-wait_file_reply(From, Ref) ->
+ Ref = erlang:monitor(process, Io),
+ Io ! {file_request,self(),Ref,Request},
receive
- {file_reply,From,Reply} ->
- erlang:demonitor(Ref),
- receive {'DOWN', Ref, _, _, _} -> ok after 0 -> ok end,
- %% receive {'EXIT', From, _} -> ok after 0 -> ok end,
+ {file_reply,Ref,Reply} ->
+ erlang:demonitor(Ref, [flush]),
Reply;
{'DOWN', Ref, _, _, _} ->
- %% receive {'EXIT', From, _} -> ok after 0 -> ok end,
{error, terminated}
end.
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index fad2ed7fb3..07fb55f390 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -92,8 +92,7 @@ do_start(Spawn, Owner, FileName, ModeList) ->
Mref = erlang:monitor(process, Pid),
receive
{Ref, {error, _Reason} = Error} ->
- erlang:demonitor(Mref),
- receive {'DOWN', Mref, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
Error;
{Ref, ok} ->
erlang:demonitor(Mref),
diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl
index 49ec6f96cc..d036dbb516 100644
--- a/lib/kernel/src/file_server.erl
+++ b/lib/kernel/src/file_server.erl
@@ -317,8 +317,7 @@ do_start_slave(start, Filer, Name) ->
SlaveMonitor = erlang:monitor(process, Slave),
receive
{started, Token} ->
- erlang:demonitor(SlaveMonitor),
- receive {'DOWN', SlaveMonitor, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(SlaveMonitor, [flush]),
{ok, Slave};
{'DOWN', SlaveMonitor, _, _, Reason} ->
exit(Reason)
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 74ad192802..acc116df84 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -39,7 +39,9 @@
{active, true | false | once} |
{buffer, non_neg_integer()} |
{dontroute, boolean()} |
+ {high_msgq_watermark, pos_integer()} |
{linger, {boolean(), non_neg_integer()}} |
+ {low_msgq_watermark, pos_integer()} |
{mode, list | binary} | list | binary |
{priority, non_neg_integer()} |
{recbuf, non_neg_integer()} |
@@ -68,7 +70,9 @@
active |
buffer |
dontroute |
+ high_msgq_watermark |
linger |
+ low_msgq_watermark |
mode |
priority |
recbuf |
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index c5a1173575..fb5737f82e 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -34,6 +34,8 @@
{dontroute, boolean()} |
{drop_membership, {inet:ip_address(), inet:ip_address()}} |
{header, non_neg_integer()} |
+ {high_msgq_watermark, pos_integer()} |
+ {low_msgq_watermark, pos_integer()} |
{mode, list | binary} | list | binary |
{multicast_if, inet:ip_address()} |
{multicast_loop, boolean()} |
@@ -56,6 +58,8 @@
deliver |
dontroute |
header |
+ high_msgq_watermark |
+ low_msgq_watermark |
mode |
multicast_if |
multicast_loop |
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 9670271b2e..aada1252ad 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -712,7 +712,8 @@ udp_options() ->
[tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
- add_membership, drop_membership, read_packets,raw].
+ add_membership, drop_membership, read_packets,raw,
+ high_msgq_watermark, low_msgq_watermark].
udp_options(Opts, Family) ->
@@ -766,7 +767,7 @@ udp_add(Name, Val, R, Opts, As) ->
sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf,
- recbuf, ipv6_v6only,
+ recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
% Other options are SCTP-specific (though they may be similar to their
% TCP and UDP counter-parts):
diff --git a/lib/kernel/src/inet_gethost_native.erl b/lib/kernel/src/inet_gethost_native.erl
index db3e44ce6f..df866660b4 100644
--- a/lib/kernel/src/inet_gethost_native.erl
+++ b/lib/kernel/src/inet_gethost_native.erl
@@ -503,8 +503,7 @@ getit(Req, DefaultName) ->
Pid, Reason} ->
{error, Reason}
end,
- catch erlang:demonitor(Ref2),
- receive {'DOWN',Ref2,_,_,_} -> ok after 0 -> ok end,
+ catch erlang:demonitor(Ref2, [flush]),
Res2
end.
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 000119bc74..a01c733d81 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -141,8 +141,8 @@
-define(INET_LOPT_READ_PACKETS, 33).
-define(INET_OPT_RAW, 34).
-define(INET_LOPT_TCP_SEND_TIMEOUT_CLOSE, 35).
--define(INET_LOPT_TCP_MSGQ_HIWTRMRK, 36).
--define(INET_LOPT_TCP_MSGQ_LOWTRMRK, 37).
+-define(INET_LOPT_MSGQ_HIWTRMRK, 36).
+-define(INET_LOPT_MSGQ_LOWTRMRK, 37).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index 742c000cc1..ded03361ee 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -126,7 +126,7 @@ verify_executable(Name0, [Ext|Rest], OrigExtensions) ->
end;
verify_executable(Name, [], OrigExtensions) when OrigExtensions =/= [""] -> %% Windows
%% Will only happen on windows, hence case insensitivity
- case can_be_full_name(string:to_lower(Name),OrigExtensions) of
+ case can_be_full_name(string:to_lower(Name),OrigExtensions) of
true ->
verify_executable(Name,[""],[""]);
_ ->
@@ -150,7 +150,7 @@ split_path(Path) ->
{win32, _} ->
{ok,Curr} = file:get_cwd(),
split_path(Path, $;, [], [Curr]);
- _ ->
+ _ ->
split_path(Path, $:, [], [])
end.
@@ -187,11 +187,14 @@ cmd(Cmd) ->
{unix, _} ->
unix_cmd(Cmd);
{win32, Wtype} ->
- Command = case {os:getenv("COMSPEC"),Wtype} of
+ Command0 = case {os:getenv("COMSPEC"),Wtype} of
{false,windows} -> lists:concat(["command.com /c", Cmd]);
{false,_} -> lists:concat(["cmd /c", Cmd]);
{Cspec,_} -> lists:concat([Cspec," /c",Cmd])
end,
+ %% open_port/2 awaits string() in Command, but io_lib:chars() can be
+ %% deep lists according to io_lib module description.
+ Command = lists:flatten(Command0),
Port = open_port({spawn, Command}, [stream, in, eof, hide]),
get_data(Port, [])
end.
@@ -213,7 +216,7 @@ unix_cmd(Cmd) ->
end.
%% The -s flag implies that only the positional parameters are set,
-%% and the commands are read from standard input. We set the
+%% and the commands are read from standard input. We set the
%% $1 parameter for easy identification of the resident shell.
%%
-define(SHELL, "/bin/sh -s unix:cmd 2>&1").
@@ -226,7 +229,7 @@ unix_cmd(Cmd) ->
-spec start_port() -> port().
start_port() ->
Ref = make_ref(),
- Request = {Ref,self()},
+ Request = {Ref,self()},
{Pid, Mon} = case whereis(?PORT_CREATOR_NAME) of
undefined ->
spawn_monitor(fun() ->
@@ -273,7 +276,7 @@ start_port_srv_handle({Ref,Client}) ->
Port
catch
error:Reason ->
- {Reason,erlang:get_stacktrace()}
+ {Reason,erlang:get_stacktrace()}
end,
Client ! {Ref,Reply}.
@@ -355,16 +358,16 @@ get_data(Port, Sofar) ->
{Port, {data, Bytes}} ->
get_data(Port, [Sofar|Bytes]);
{Port, eof} ->
- Port ! {self(), close},
+ Port ! {self(), close},
receive
{Port, closed} ->
true
- end,
+ end,
receive
- {'EXIT', Port, _} ->
+ {'EXIT', Port, _} ->
ok
after 1 -> % force context switch
ok
- end,
+ end,
lists:flatten(Sofar)
end.
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index 7c965ca384..83e0b59cc2 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -388,13 +388,8 @@ server_call(Node, Name, ReplyWrapper, Msg)
{'DOWN', Ref, _, _, _} ->
{error, nodedown};
{ReplyWrapper, Node, Reply} ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, _, _, _} ->
- Reply
- after 0 ->
- Reply
- end
+ erlang:demonitor(Ref, [flush]),
+ Reply
end
end.
@@ -501,17 +496,6 @@ start_monitor(Node, Name) ->
{Node,erlang:monitor(process, {Name, Node})}
end.
-%% Cancels a monitor started with Ref=erlang:monitor(_, _),
-%% i.e return value {Node, Ref} from start_monitor/2 above.
-unmonitor(Ref) when is_reference(Ref) ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, _, _, _} ->
- true
- after 0 ->
- true
- end.
-
%% Call apply(M,F,A) on all nodes in parallel
-spec multicall(Module, Function, Args) -> {ResL, BadNodes} when
@@ -635,10 +619,10 @@ rec_nodes(Name, [{N,R} | Tail], Badnodes, Replies) ->
rec_nodes(Name, Tail, [N|Badnodes], Replies);
{?NAME, N, {nonexisting_name, _}} ->
%% used by sbcast()
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes(Name, Tail, [N|Badnodes], Replies);
{Name, N, Reply} -> %% Name is bound !!!
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes(Name, Tail, Badnodes, [Reply|Replies])
end.
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index c604e7073f..4218cfa646 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -91,6 +91,8 @@
-export([standard_io/1,mini_server/1]).
+-export([old_io_protocol/1]).
+
%% Debug exports
-export([create_file_slow/2, create_file/2, create_bin/2]).
-export([verify_file/2, verify_bin/3]).
@@ -114,7 +116,7 @@ all() ->
delayed_write, read_ahead, segment_read, segment_write,
ipread, pid2name, interleaved_read_write, otp_5814, otp_10852,
large_file, large_write, read_line_1, read_line_2, read_line_3,
- read_line_4, standard_io].
+ read_line_4, standard_io, old_io_protocol].
groups() ->
[{dirs, [], [make_del_dir, cur_dir_0, cur_dir_1,
@@ -310,6 +312,31 @@ standard_io(Config) when is_list(Config) ->
Pid ! die,
receive after 1000 -> ok end.
+old_io_protocol(suite) ->
+ [];
+old_io_protocol(doc) ->
+ ["Test that the old file IO protocol =< R16B still works"];
+old_io_protocol(Config) when is_list(Config) ->
+ Dog = test_server:timetrap(test_server:seconds(5)),
+ RootDir = ?config(priv_dir,Config),
+ Name = filename:join(RootDir,
+ atom_to_list(?MODULE)
+ ++"old_io_protocol.fil"),
+ MyData = "0123456789abcdefghijklmnopqrstuvxyz",
+ ok = ?FILE_MODULE:write_file(Name, MyData),
+ {ok, Fd} = ?FILE_MODULE:open(Name, write),
+ Fd ! {file_request,self(),Fd,truncate},
+ receive
+ {file_reply,Fd,ok} -> ok
+ end,
+ ok = ?FILE_MODULE:close(Fd),
+ {ok, <<>>} = ?FILE_MODULE:read_file(Name),
+ test_server:timetrap_cancel(Dog),
+ [] = flush(),
+ ok.
+
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
read_write_file(suite) -> [];
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index 2a886b2efc..c5d8becfd3 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -1399,8 +1399,7 @@ s_req(S, Req) ->
{'DOWN',Mref,_,_,Error} ->
exit(Error);
{S,Mref,Reply} ->
- erlang:demonitor(Mref),
- receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
Reply
end.
diff --git a/lib/kernel/test/global_SUITE_data/global_trace.erl b/lib/kernel/test/global_SUITE_data/global_trace.erl
index 4f253baac4..ddbe608c0a 100644
--- a/lib/kernel/test/global_SUITE_data/global_trace.erl
+++ b/lib/kernel/test/global_SUITE_data/global_trace.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -122,12 +123,12 @@ state(Else) ->
%%% {ops,Ops}]
%%% NewKnown = Known ++ AddedNodes
%%% AddedNodes = NewNodes -- Known
-%%% NewNodes �r h�r den man f�rhandlat med plus de noder den k�nner till.
+%%% NewNodes är här den man förhandlat med plus de noder den känner till.
%%% {added, AddedNodes}, Extra = [{ops,Ops}]
%%% NewKnown = Known ++ AddedNodes
-%%% Den (passiva) noden f�r Nodes som �r NewNodes
-%%% hos den f�rhandlande. Sedan: AddedNodes = (Nodes -- Known) -- [node()].
-%%% Det �r som hos f�rhandlaren.
+%%% Den (passiva) noden får Nodes som är NewNodes
+%%% hos den förhandlande. Sedan: AddedNodes = (Nodes -- Known) -- [node()].
+%%% Det är som hos förhandlaren.
%%% {nodes_changed, {New,Old}}
%%% Every now and then the list [node() | nodes()] is checked for updates.
%%% New are the nodes that global does not know of (yet).
diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl
index 75496ce745..185751fead 100644
--- a/lib/kernel/test/inet_sockopt_SUITE.erl
+++ b/lib/kernel/test/inet_sockopt_SUITE.erl
@@ -772,8 +772,10 @@ all_listen_options() ->
{mode,list,binary,true,true},
{deliver,term,port,true,true},
{exit_on_close, true, false, true, true},
- %{high_watermark,4096,8192,true,true},
- %{low_watermark,2048,4096,true,true},
+ {high_watermark,4096,8192,true,true},
+ {low_watermark,2048,4096,true,true},
+ {high_msgq_watermark,4096,8192,true,true},
+ {low_msgq_watermark,2048,4096,true,true},
{send_timeout,infinity,1000,true,true},
{send_timeout_close,false,true,true,true},
{delay_send,false,true,true,true},
@@ -797,6 +799,8 @@ all_connect_options() ->
{exit_on_close, true, false, true, true},
{high_watermark,4096,8192,false,true},
{low_watermark,2048,4096,false,true},
+ {high_msgq_watermark,4096,8192,true,true},
+ {low_msgq_watermark,2048,4096,true,true},
{send_timeout,infinity,1000,true,true},
{send_timeout_close,false,true,true,true},
{delay_send,false,true,true,true},
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 382fd6f6a9..73ed704ae3 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -18,20 +18,21 @@
%%
-module(os_SUITE).
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
+-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
-export([space_in_cwd/1, quoting/1, space_in_name/1, bad_command/1,
- find_executable/1, unix_comment_in_command/1, evil/1]).
+ find_executable/1, unix_comment_in_command/1, deep_list_command/1, evil/1]).
-include_lib("test_server/include/test_server.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
+all() ->
[space_in_cwd, quoting, space_in_name, bad_command,
- find_executable, unix_comment_in_command, evil].
+ find_executable, unix_comment_in_command, deep_list_command,
+ evil].
-groups() ->
+groups() ->
[].
init_per_suite(Config) ->
@@ -117,9 +118,9 @@ space_in_name(Config) when is_list(Config) ->
?line ok = file:change_mode(Echo, 8#777), % Make it executable on Unix.
%% Run the echo program.
- %% Quoting on windows depends on if the full path of the executable
+ %% Quoting on windows depends on if the full path of the executable
%% contains special characters. Paths when running common_tests always
- %% include @, why Windows would always fail if we do not double the
+ %% include @, why Windows would always fail if we do not double the
%% quotes (this is the behaviour of cmd.exe, not Erlang's idea).
Quote = case os:type() of
{win32,_} ->
@@ -135,7 +136,7 @@ space_in_name(Config) when is_list(Config) ->
?t:sleep(5),
?line [] = receive_all(),
ok.
-
+
bad_command(doc) ->
"Check that a bad command doesn't crasch the server or the emulator (it used to).";
bad_command(suite) -> [];
@@ -153,17 +154,17 @@ find_executable(suite) -> [];
find_executable(doc) -> [];
find_executable(Config) when is_list(Config) ->
case os:type() of
- {win32, _} ->
+ {win32, _} ->
?line DataDir = filename:join(?config(data_dir, Config), "win32"),
?line ok = file:set_cwd(filename:join([DataDir, "current"])),
?line Bin = filename:join(DataDir, "bin"),
?line Abin = filename:join(DataDir, "abin"),
?line UsrBin = filename:join([DataDir, "usr", "bin"]),
?line {ok, Current} = file:get_cwd(),
-
+
?line Path = lists:concat([Bin, ";", Abin, ";", UsrBin]),
?line io:format("Path = ~s", [Path]),
-
+
%% Search for programs in Bin (second element in PATH).
?line find_exe(Abin, "my_ar", ".exe", Path),
?line find_exe(Abin, "my_ascii", ".com", Path),
@@ -175,18 +176,18 @@ find_executable(Config) when is_list(Config) ->
?line find_exe(Abin, "my_ar.EXE", "", Path),
?line find_exe(Abin, "my_ascii.COM", "", Path),
?line find_exe(Abin, "MY_ADB.BAT", "", Path),
-
+
%% Search for programs in Abin (second element in PATH).
?line find_exe(Abin, "my_ar", ".exe", Path),
?line find_exe(Abin, "my_ascii", ".com", Path),
?line find_exe(Abin, "my_adb", ".bat", Path),
-
+
%% Search for programs in the current working directory.
?line find_exe(Current, "my_program", ".exe", Path),
?line find_exe(Current, "my_command", ".com", Path),
?line find_exe(Current, "my_batch", ".bat", Path),
ok;
- {unix, _} ->
+ {unix, _} ->
DataDir = ?config(data_dir, Config),
%% Smoke test.
@@ -237,6 +238,21 @@ unix_comment_in_command(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+deep_list_command(doc) ->
+ "Check that a deep list in command works equally on unix and on windows.";
+deep_list_command(suite) -> [];
+deep_list_command(Config) when is_list(Config) ->
+ %% As a 'io_lib' module description says: "There is no guarantee that the
+ %% character lists returned from some of the functions are flat, they can
+ %% be deep lists."
+ %% That's why os:cmd/1 can have arguments that are deep lists.
+ %% It is not a problem for unix, but for windows it is (in R15B02 for ex.).
+ Echo = os:cmd([$e, $c, "ho"]),
+ true = erlang:is_list(Echo),
+ %% FYI: [$e, $c, "ho"] =:= io_lib:format("ec~s", ["ho"])
+ ok.
+
+
-define(EVIL_PROCS, 100).
-define(EVIL_LOOPS, 100).
-define(PORT_CREATOR, os_cmd_port_creator).
@@ -303,4 +319,3 @@ receive_all() ->
X -> [X|receive_all()]
after 0 -> []
end.
-
diff --git a/lib/megaco/.gitignore b/lib/megaco/.gitignore
index 1c5979cd62..3e64dc20f5 100644
--- a/lib/megaco/.gitignore
+++ b/lib/megaco/.gitignore
@@ -1,3 +1,38 @@
+# Files generated by configure.
+/configure
+/config.log
+/config.status
+
+# Files generated when building/running tests
+/test/*.log
+/test/*.beam
+
+# Generated documentation. (ie. not doc/src)
+/doc/[^s]*
+
+# Library links
+/priv/lib/*.so
+
+# Generated text src
+/src/text/megaco_text_mini_parser.erl
+/src/text/megaco_text_parser_*.erl
+
+# Generated binary src and stuff...
+# /src/binary/megaco_per_media_gateway_control_*.erl
+# /src/binary/megaco_per_media_gateway_control_*.asn1db
+/src/binary/megaco_*_media_gateway_control_*.hrl
+/src/binary/megaco_*_media_gateway_control_*.erl
+/src/binary/megaco_*_media_gateway_control_*.asn1db
+
+# Generated binary src and stuff...
+/src/flex/megaco_flex_scanner_drv.c
+/src/flex/megaco_flex_scanner_drv.flex
+/src/flex/megaco_flex_scanner_drv_mt.c
+/src/flex/megaco_flex_scanner_drv_mt.flex
+
+# Generated examples stuff...
examples/meas/Makefile
examples/meas/meas.sh.skel
examples/meas/mstone1.sh.skel
+
+
diff --git a/lib/megaco/doc/src/Makefile b/lib/megaco/doc/src/Makefile
index f35413a4fd..ea2284e89b 100644
--- a/lib/megaco/doc/src/Makefile
+++ b/lib/megaco/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2012. All Rights Reserved.
+# Copyright Ericsson AB 2000-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
@@ -123,9 +123,6 @@ imgs: $(IMG_FILES:%=$(HTMLDIR)/%)
man: $(MAN3_FILES)
$(INDEX_TARGET): $(INDEX_SRC) $(APP_FILE)
- sed -e 's/%VSN%/$(VSN)/' $< > $@
-
-$(INDEX_TARGET): $(INDEX_SRC) $(APP_FILE)
sed -e 's/%VSN%/$(VSN)/' \
-e 's/%ERLANG_SITE%/www\.erlang\.se\//' \
-e 's/%UP_ONE_LEVEL%/..\/..\/..\/doc\/index.html/' \
diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml
index bb30ce4c2a..91905b76f7 100644
--- a/lib/megaco/doc/src/notes.xml
+++ b/lib/megaco/doc/src/notes.xml
@@ -36,24 +36,138 @@
section is the version number of Megaco.</p>
+ <section><title>Megaco 3.17</title>
+
+ <p>Version 3.17 supports code replacement in runtime from/to
+ version 3.16.0.3 and and 3.16.0.2. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Allow whitespaces in installation path. </p>
+ <p>It is now possible to give configure and make an
+ installation/release path with whitespaces in it. </p>
+ <p>Own Id: OTP-10107</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>Buffer overrun error while flex scanner processing
+ property parm groups. </p>
+ <p>This error occured only for large messages if a
+ buffer realloc was needed while processing the
+ property parm groups. </p>
+ <p>Own Id: OTP-10998</p>
+ <p>Aux Id: Seq 12263</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>A number of binary encoding alternatives has been removed.
+ The binary encoding option <c>driver</c> has been removed
+ since this (the use of the asn1 linked in driver) is
+ now default and there is now way to <em>not</em> use it.
+ See <seealso marker="megaco_encode#binary_config">configuration of binary encoding</seealso> for more info. </p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ </section> <!-- 3.17 -->
+
+
<section><title>Megaco 3.16.0.3</title>
- <section><title>Improvements and New Features</title>
- <list>
+ <p>Version 3.16.0.2 supports code replacement in runtime from/to
+ version 3.16.0.1, 3.16, 3.15.1.1, 3.15.1 and 3.15.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
<item>
- <p>Where necessary a comment stating encoding has been
- added to Erlang files. The comment is meant to be removed
- in Erlang/OTP R17B when UTF-8 becomes the default
- encoding. </p>
- <p>
- Own Id: OTP-10630</p>
+ <p>Where necessary, a comment stating encoding has been
+ added to Erlang files. The comment is meant to be removed
+ in Erlang/OTP R17B when UTF-8 becomes the default encoding. </p>
+ <p>Own Id: OTP-10630</p>
</item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>Fixing miscellaneous things detected by dialyzer. </p>
+ <p>Own Id: OTP-9075</p>
+ </item>
+
</list>
+ -->
+
</section>
-</section>
+ <section>
+ <title>Incompatibilities</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>A number of binary encoding alternatives has been removed.
+ The binary encoding option <c>driver</c> has been removed
+ since this (the use of the asn1 linked in driver) is
+ now default and there is now way to <em>not</em> use it.
+ See <seealso marker="megaco_encode#binary_config">configuration of binary encoding</seealso> for more info. </p>
+ </item>
+
+ </list>
-<section><title>Megaco 3.16.0.2</title>
+ </section>
+
+ </section> <!-- 3.16.0.3 -->
+
+
+ <section><title>Megaco 3.16.0.2</title>
<p>Version 3.16.0.2 supports code replacement in runtime from/to
version 3.16.0.1, 3.16, 3.15.1.1, 3.15.1 and 3.15.</p>
@@ -657,653 +771,6 @@
</section> <!-- 3.13 -->
- <section>
- <title>Megaco 3.12</title>
-
-<!--
- <p>Version 3.12 supports code replacement in runtime from/to
- version 3.11.3.</p>
--->
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Improve handling of async transaction reply. </p>
- <p>For asynchronous requests, issued using
- <seealso marker="megaco#cast">megaco:cast/3</seealso>,
- the reply will be delivered using the
- <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
- callback function. </p>
- <p>If a receiver of a request, issued using
- <seealso marker="megaco#cast">megaco:cast/3</seealso>,
- does not reply in time, megaco re-sends the request.
- If the receiver of the request sends the reply at the same
- time as megaco re-sends, it may also send a reply to the
- resent request (thinking the first reply got lost). These
- two replies may arrive more or less at the same time,
- causing confusion. </p>
- <p>In order to improve this situation, a number of
- improvements have been done: </p>
- <list type="bulleted">
- <item>
- <p>When the first reply arrives, a timer, request-keep-alive,
- is started. This timer is used to decide when to stop
- accepting replies as legitimate. </p>
- <p>The timeout time for the timer is specified by the
- config option <em>request_keep_alive_timout</em>,
- which can be set per
- <seealso marker="megaco#ui_request_keep_alive_timeout">user</seealso>
- or per
- <seealso marker="megaco#ci_request_keep_alive_timeout">connection</seealso>. </p>
- </item>
- <item>
- <p>We also keep track of how many replies has been received
- (we do this as long as the request-keep-alive timer is
- running). </p>
- </item>
- <item>
- <p>Each reply that arrives while the request-keep-alive timer
- is running (including the first) will be delivered using the
- <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
- callback function, but with the UserReply augmented to
- include a serial number indicating which reply number this
- is.
- The <em>first</em> reply to arrive,
- will be numbered <em>one (1)</em>. </p>
- </item>
- <item>
- <p>Replies arriving after the timer has expired will be delivered
- in the same way as before, using the
- <seealso marker="megaco_user#unexpected_trans">handle_unexpected_trans/3,4</seealso>
- callback function. </p>
- </item>
- <item>
- <p>Note that if the timer was <em>not</em> configured,
- megaco will act exactly as before! </p>
- </item>
- </list>
- <p>Own Id: OTP-8183</p>
- <p>Aux Id: Seq 11393</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>If the megaco app received a transaction reply, for a request
- issued using the
- <seealso marker="megaco#call">call/3</seealso> function, from
- the wrong remote entity (wrong MId)), megaco would still deliver
- the reply (<seealso marker="megaco#call">call/3</seealso>
- returnes) as if from the correct remote entity (right MId). </p>
- <p>This has been changed so that the function now returns with
- an error reason. </p>
- <p>See <seealso marker="megaco#call">call/3</seealso> for more
- info. </p>
- <p>*** POTENTIAL INCOMPATIBILITY ***</p>
- <p>Own Id: OTP-8212</p>
- <p>Aux Id: Seq 11305</p>
- </item>
-
- </list>
-
- </section>
-
- </section> <!-- 3.12 -->
-
-
- <section>
- <title>Megaco 3.11.3</title>
-
-<!--
- <p>Version 3.11.3 supports code replacement in runtime from/to
- version 3.11.2, 3.11.1 and 3.11.</p>
--->
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Replacing obsolete guard tests.</p>
- <p>Own Id: OTP-8164</p>
- <!-- <p>Aux Id: Seq 11332</p> -->
- </item>
-
- <item>
- <p>Added the config option
- <seealso marker="megaco#ui_call_proxy_gc_timeout">call_proxy_gc_timeout</seealso>
- to be able to control the way unexpected replies (when requests issued
- via calls to <seealso marker="megaco#call">call/3</seealso>)
- are handled. </p>
- <p>See
- <seealso marker="megaco#user_info">user_info/2</seealso>,
- <seealso marker="megaco#conn_info">conn_info/2</seealso> and
- <seealso marker="megaco#call">call/3</seealso> for more info. </p>
- <p>Own Id: OTP-8167</p>
- <p>Aux Id: Seq 11393</p>
- </item>
-
- <item>
- <p>Make flex scanner c89 compiler compliant.</p>
- <p>Akira Kitada</p>
- <p>Own Id: OTP-8191</p>
- <!-- <p>Aux Id: Seq 11332</p> -->
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>Replacing obsolete guard tests.</p>
- <p>Own Id: OTP-8164</p>
- <p>Aux Id: Seq 11332</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>For those implementing their own codec's, the new megaco_encoder
- behaviour will require three more functions. See above for more
- info. </p>
- <p>Own Id: OTP-7168</p>
- <p>Aux Id: Seq 10867</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.11.3 -->
-
-
- <section>
- <title>Megaco 3.11.2</title>
-
- <p>Version 3.11.2 supports code replacement in runtime from/to
- version 3.11.1 and 3.11.</p>
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Megaco was unnecessarily strict when parsing the SDP
- attribute <c>maxptime</c> (leading or trailing spaces
- cased the value parse to fail). </p>
- <p>This has been improved so that leading and trailing
- spaces are stripped before parsing the value.
- The same has been done for the attribute <c>ptime</c>.</p>
- <p>Own Id: OTP-8123</p>
- <p>Aux Id: Seq 11364</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>[text] The <em>unquoted</em> string BOTH was interpreted as the
- <c>'BothToken'</c> token. This was a version 3 (prev3a, prev3b,
- prev3c and v3) only. </p>
- <p>Own Id: OTP-8114</p>
- <p>Aux Id: Seq 11353</p>
- </item>
-
- <item>
- <p>The reply proxy could crash if the timeout time calculation
- results in a negative number. This will result in a function
- clause with resulting error report.</p>
- <p>Own Id: OTP-8081</p>
- <p>Aux Id: Seq 11332</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>For those implementing their own codec's, the new megaco_encoder
- behaviour will require three more functions. See above for more
- info. </p>
- <p>Own Id: OTP-7168</p>
- <p>Aux Id: Seq 10867</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.11.2 -->
-
-
- <section>
- <title>Megaco 3.11.1</title>
-
- <p>Version 3.11.1 supports code replacement in runtime from/to
- version 3.11.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>In order to better utilize multi-core procs, the
- <c>flex</c> (text) scanner has been improved. </p>
- <p>The <c>flex</c> (text) scanner has been made reentrant,
- <em>if</em> the flex utility supports this. Note that the version
- of <c>flex</c> supplied with some OS/distros (Solaris 10,
- FreeBSD and OpenBSD to mention a few) may not support this, in which
- case the flex scanner will be non-reentrant, just as before. </p>
- <p>Own Id: OTP-7302</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>[text] The <em>unquoted</em> string BOTH was interpreted as the
- <c>'BothToken'</c> token. This was a version 3 (prev3a, prev3b,
- prev3c and v3) only. </p>
- <p>Own Id: OTP-8114</p>
- <p>Aux Id: Seq 11353</p>
- </item>
-
- <item>
- <p>The reply proxy could crash if the timeout time calculation
- results in a negative number. This will result in a function
- clause with resulting error report.</p>
- <p>Own Id: OTP-8081</p>
- <p>Aux Id: Seq 11332</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>For those implementing their own codec's, the new megaco_encoder
- behaviour will require three more functions. See above for more
- info. </p>
- <p>Own Id: OTP-7168</p>
- <p>Aux Id: Seq 10867</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.11.1 -->
-
-
- <section>
- <title>Megaco 3.11</title>
-
-<!--
- <p>Version 3.11 supports code replacement in runtime from/to
- version 3.10.1 and 3.10.0.1.</p>
--->
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>In order to better utilize multi-core procs, the
- <c>flex</c> (text) scanner has been improved. </p>
- <p>The <c>flex</c> (text) scanner has been made reentrant,
- <em>if</em> the flex utility supports this. Note that the version
- of <c>flex</c> supplied with some OS/distros (Solaris 10,
- FreeBSD and OpenBSD to mention a few) may not support this, in which
- case the flex scanner will be non-reentrant, just as before. </p>
- <p>Own Id: OTP-7302</p>
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>The (plain) text scanner could incorrectly identify
- character strings (any 17 char long string with the
- char t in the middle) as a TimeStampToken.</p>
- <p>Own Id: OTP-7249</p>
- <p>Aux Id: Seq 10917</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>For those implementing their own codec's, the new megaco_encoder
- behaviour will require three more functions. See above for more
- info. </p>
- <p>Own Id: OTP-7168</p>
- <p>Aux Id: Seq 10867</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.11 -->
-
-
- <section>
- <title>Megaco 3.10.1</title>
-
- <p>Version 3.10.1 supports code replacement in runtime from/to
- version 3.10.0.1, 3.10 and 3.9.4.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own Id: OTP-7851</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- </list>
--->
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Unexpected
- <seealso marker="megaco_user#unexpected_trans">handle_unexpected_reply</seealso>
- callbacks. </p>
- <p>The <seealso marker="megaco_user">megaco_user</seealso> callback
- function
- <seealso marker="megaco_user#unexpected_trans">handle_unexpected_reply</seealso>
- could during high load be called with unexpected values for the Trans
- argument, such as an <c>TransactionReply</c> where
- <c>transactionResult</c> had the value <c>{error, timeout}</c>.
- This was a result of a race condition and has now been fixed. </p>
- <p>Own Id: OTP-7926</p>
- <p>Aux Id: Seq 11255</p>
- </item>
-
- <item>
- <p>[text] PropertyParm values cannot be quoted. </p>
- <p>It was not possible to encode a PropertyParm value as a quoted string
- (unless it *had* to (has at least one RestChar)). The megaco text codec's
- now also accepts quoted strings as PropertyParm values. </p>
- <p>Own Id: OTP-7936</p>
- <p>Aux Id: Seq 11258</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>If the transport module calls the
- <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
- or
- <seealso marker="megaco#receive_message">receive_message/5</seealso>
- function(s) for the initial message, then the
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>
- function will now be called and not the
- <seealso marker="megaco_user#connect">handle_connect/2</seealso>
- function. </p>
- <p>Own Id: OTP-7713</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.10.1 -->
-
-
- <section>
- <title>Megaco 3.10.0.1</title>
-
- <p>Version 3.10.0.1 supports code replacement in runtime from/to
- version 3.10 and 3.9.4 except
- when using any of the drivers (flex for text or asn1 for binary).</p>
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own Id: OTP-7851</p>
- <!-- <p>Aux Id: Seq 11140</p> -->
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>Memory leak in the flex scanner. There was a memory
- leak in the flex scanner function handling
- Property Parameters. </p>
- <p>Own Id: OTP-7700</p>
- <p>Aux Id: Seq 11126</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>If the transport module calls the
- <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
- or
- <seealso marker="megaco#receive_message">receive_message/5</seealso>
- function(s) for the initial message, then the
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>
- function will now be called and not the
- <seealso marker="megaco_user#connect">handle_connect/2</seealso>
- function. </p>
- <p>Own Id: OTP-7713</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.10.0.1 -->
-
-
- <section>
- <title>Megaco 3.10</title>
-
- <p>Version 3.10 supports code replacement in runtime from/to
- version 3.9.4, 3.9.3, 3.9.2, 3.9.1.1, 3.9.1, 3.9, 3.8.2, 3.8.1 and 3.8 except
- when using any of the drivers (flex for text or asn1 for binary).</p>
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Added new API function
- <seealso marker="megaco#connect">megaco:connect/5</seealso> and
- the corresponding new <c>megaco_user</c> callback function
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>.
- The purpose of this is to be able to pass information to the
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>
- function by calling the
- <seealso marker="megaco#connect">megaco:connect/5</seealso>
- function. </p>
- <p>Own Id: OTP-7713</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- <item>
- <p>Update file headers with new copyright notice. </p>
- <p>Own Id: OTP-7743</p>
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>Memory leak in the flex scanner. There was a memory
- leak in the flex scanner function handling
- Property Parameters. </p>
- <p>Own Id: OTP-7700</p>
- <p>Aux Id: Seq 11126</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>If the transport module calls the
- <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
- or
- <seealso marker="megaco#receive_message">receive_message/5</seealso>
- function(s) for the initial message, then the
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>
- function will now be called and not the
- <seealso marker="megaco_user#connect">handle_connect/2</seealso>
- function. </p>
- <p>Own Id: OTP-7713</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- </list>
-
- </section>
- </section> <!-- 3.10 -->
-
<!-- section>
<title>Release notes history</title>
<p>For information about older versions see
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
index a7b38eb107..b3659366a4 100644
--- a/lib/megaco/src/app/megaco.appup.src
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -2,7 +2,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
@@ -18,186 +18,170 @@
%% %CopyrightEnd%
%%
-%%
-%% 3.4.3
-%% |
-%% v
-%% 3.4.4
-%% / \
-%% | |
-%% v v
-%% 3.5 3.4.5
-%% | |
-%% v v
-%% 3.5.1 <- 3.4.6
-%% |
-%% v
-%% 3.5.2
-%% |
-%% v
-%% 3.5.3
-%% |
-%% v
-%% 3.6
-%% |
-%% v
-%% 3.6.0.1
-%% |
-%% v
-%% 3.6.1
-%% |
-%% v
-%% 3.6.2
-%% / \
-%% | |
-%% v |
-%% 3.7 3.6.3
-%% | |
-%% v v
-%% 3.7.1 <- 3.6.4
-%% | |
-%% v v
-%% 3.7.2 <- 3.6.5
-%% | |
-%% v v
-%% 3.7.3 <- 3.6.6
-%% | |
-%% v v
-%% 3.7.4 <- 3.6.7
-%% | |
-%% v v
-%% 3.7.5 <- 3.6.9
-%% |
-%% v
-%% 3.8
-%% |
-%% v
-%% 3.8.1
-%% |
-%% v
-%% 3.8.2
-%% |
-%% v
-%% 3.9
-%% |
-%% v
-%% 3.9.1
-%% |
-%% v
-%% 3.9.1.1
-%% |
-%% v
-%% 3.9.2
-%% |
-%% v
-%% 3.9.3
-%% |
-%% v
-%% 3.9.4
-%% |
-%% v
-%% 3.10
-%% |
-%% v
-%% 3.10.0.1
-%% |
-%% v
-%% 3.10.1
-%% |
-%% v
-%% 3.11
-%% |
-%% v
-%% 3.11.1
-%% |
-%% v
-%% 3.11.2
-%% |
-%% v
-%% 3.11.3
-%% |
-%% v
-%% 3.12
-%% |
-%% v
-%% 3.13
-%% |
-%% v
-%% 3.14
-%% |
-%% v
-%% 3.14.1
-%% |
-%% v
-%% 3.14.1.1
-%% |
-%% v
-%% 3.15
-%% |
-%% v
-%% 3.15.1
-%% |
-%% v
-%% 3.15.1.1
-%% |
-%% v
-%% 3.16
-%% |
-%% v
-%% 3.16.0.1
-%% |
-%% v
-%% 3.16.0.2
+%%
+%% 3.4.3
+%% |
+%% v
+%% 3.4.4
+%% / \
+%% | |
+%% v v
+%% 3.5 3.4.5
+%% | |
+%% v v
+%% 3.5.1 <- 3.4.6
+%% |
+%% v
+%% 3.5.2
+%% |
+%% v
+%% 3.5.3
+%% |
+%% v
+%% 3.6
+%% |
+%% v
+%% 3.6.0.1
+%% |
+%% v
+%% 3.6.1
+%% |
+%% v
+%% 3.6.2
+%% / \
+%% | |
+%% v v
+%% 3.7 3.6.3
+%% | |
+%% v v
+%% 3.7.1 <- 3.6.4
+%% | |
+%% v v
+%% 3.7.2 <- 3.6.5
+%% | |
+%% v v
+%% 3.7.3 <- 3.6.6
+%% | |
+%% v v
+%% 3.7.4 <- 3.6.7
+%% | |
+%% v v
+%% 3.7.5 <- 3.6.9
+%% |
+%% v
+%% 3.8
+%% |
+%% v
+%% 3.8.1
+%% |
+%% v
+%% 3.8.2
+%% |
+%% v
+%% 3.9
+%% |
+%% v
+%% 3.9.1
+%% |
+%% v
+%% 3.9.1.1
+%% |
+%% v
+%% 3.9.2
+%% |
+%% v
+%% 3.9.3
+%% |
+%% v
+%% 3.9.4
+%% |
+%% v
+%% 3.10
+%% |
+%% v
+%% 3.10.0.1
+%% |
+%% v
+%% 3.10.1
+%% |
+%% v
+%% 3.11
+%% |
+%% v
+%% 3.11.1
+%% |
+%% v
+%% 3.11.2
+%% |
+%% v
+%% 3.11.3
+%% / \
+%% | \
+%% v \
+%% 3.12 \
+%% | \
+%% v \
+%% 3.13 \
+%% | \
+%% v \
+%% 3.14 \
+%% | \
+%% v \
+%% 3.14.1 \
+%% | \
+%% v \
+%% 3.14.1.1 \
+%% / \ \
+%% / \ \
+%% | \ \
+%% v \ \
+%% 3.15 \ \
+%% | \ \
+%% v \ \
+%% 3.15.1 \ \
+%% | \ \
+%% v \ \
+%% 3.15.1.1 \ \
+%% / \ \ |
+%% / \ \ |
+%% / \ \ |
+%% | \ \ |
+%% v \ \ |
+%% 3.16 \ \ |
+%% | \ \ |
+%% v \ \ |
+%% 3.16.0.1 \ | |
+%% | \ | |
+%% v \ | |
+%% 3.16.0.2 \ | |
+%% | \ \ | |
+%% | \ \ | |
+%% | \ \ | |
+%% v \ | | |
+%% 3.16.0.3 \ | | |
+%% | \ | | |
+%% | | | | |
+%% | | | | |
+%% | | | | |
+%% v v v v v
+%% 3.17 <- 3.16.1 <- 3.15.2 <- 3.14.2 <- 3.11.4
%%
%%
+
{"%VSN%",
[
- {"3.16.0.1",
- [
- ]
- },
- {"3.16",
- [
- ]
- },
- {"3.15.1.1",
- [
- {restart_application, megaco}
- ]
- },
- {"3.15.1",
- [
- {restart_application, megaco}
- ]
- },
- {"3.15",
+ {"3.16.0.3",
[
- {restart_application, megaco}
+ {update, megaco_flex_scanner_handler, {advanced, upgrade_from_pre_3_17},
+ soft_purge, soft_purge, []}
]
}
],
[
- {"3.16.0.1",
- [
- ]
- },
- {"3.16",
- [
- ]
- },
- {"3.15.1.1",
- [
- {restart_application, megaco}
- ]
- },
- {"3.15.1",
- [
- {restart_application, megaco}
- ]
- },
- {"3.15",
+ {"3.16.0.3",
[
- {restart_application, megaco}
+ {update, megaco_flex_scanner_handler, {advanced, downgrade_to_pre_3_17},
+ soft_purge, soft_purge, []}
]
}
]
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
index 3914a81b8c..90d5c2aae6 100644
--- a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
+++ b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
@@ -1,8 +1,8 @@
/*
* %CopyrightBegin%
- *
+ *
* 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
* compliance with the License. You should have received a copy of the
@@ -95,6 +95,13 @@ typedef struct {
int token_counter;
} MfsErlDrvData;
+/* IBL = In Buffer Length - the raw (un-decoded) message buffer length */
+#define TERM_SPEC_SIZE_INITIAL(IBL) (1024 + 2*(IBL))
+
+/* CTSS = Current term spec size - the current term spec length */
+/* S = Size - how many positions we need */
+#define TERM_SPEC_SIZE_NEXT(CTSS,S) ((CTSS) + 1024 + (S))
+
#if !defined(MEGACO_REENTRANT_FLEX_SCANNER)
static MfsErlDrvData mfs_drv_data;
#endif
@@ -737,7 +744,7 @@ v LOAD_TOKEN(mfs_VersionToken);
#endif
-/* #define MFS_DEBUG true */ /* temporary */
+// #define MFS_DEBUG true
#if defined(MFS_DEBUG)
# define DBG( proto ) printf proto
# define DBG_BUF(func, bufName, buf, bufSz) mfs_dbg_buf_print(func, bufName, buf, bufSz)
@@ -842,15 +849,20 @@ static void mfs_ensure_term_spec(MfsErlDrvData* dataP, int size)
"\n term_spec_size: %d\n",
dataP->term_spec_index, dataP->term_spec_size) );
- dataP->term_spec_size = (dataP->term_spec_size * 2) + size;
+ dataP->term_spec_size = TERM_SPEC_SIZE_NEXT(dataP->term_spec_size, size);
DBG( ("mfs_ensure_term_spec -> "
- "term_spec is at 0x%X, new term_spec_size is %d\n",
- (unsigned int) dataP->term_spec, dataP->term_spec_size) );
+ "term_spec is at 0x%X, new term_spec_size is %d (%lu)\n",
+ (unsigned int) dataP->term_spec,
+ dataP->term_spec_size,
+ dataP->term_spec_size * sizeof(ErlDrvTermData)) );
tmp = REALLOC(dataP->term_spec,
dataP->term_spec_size * sizeof(ErlDrvTermData));
+ DBG( ("mfs_ensure_term_spec -> "
+ "realloc result: 0x%X\n", (unsigned int) tmp) );
+
if (tmp == NULL) {
/*
* Ouch, we did'nt get any new memory.
@@ -942,6 +954,9 @@ static void mfs_octet_load_token(ErlDrvTermData TokenTag, int is_empty)
ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
ASSIGN_TERM_SPEC(dataP, 3);
+
+ DBG( ("mfs_octet_load_token -> done\n") );
+
}
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
@@ -1241,7 +1256,7 @@ static void mfs_load_property_groups(MfsErlDrvData* dataP)
} // if ((yytext[i] != SP)...
} // while ...
- mfs_ensure_term_spec(dataP, 4); // 2 + 2 just in case
+ mfs_ensure_term_spec(dataP, 6); // 3 + 3 just in case
/* Make sure we actually have some groups */
@@ -1727,7 +1742,7 @@ static ErlDrvSSizeT mfs_control(ErlDrvData handle,
dataP->text_buf = tmp;
dataP->text_ptr = tmp;
- dataP->term_spec_size = 1000 + buf_len; /* OTP-4237 */
+ dataP->term_spec_size = TERM_SPEC_SIZE_INITIAL(buf_len);
DBG( ("mfs_control -> allocate term-spec buffer: "
"\n term_spec_size: %d\n", dataP->term_spec_size) );
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_handler.erl b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
index 420202134e..ad28e25c39 100644
--- a/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
+++ b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. 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
@@ -181,11 +181,11 @@ terminate(_Reason, _S) ->
%% Returns: {ok, NewState}
%%----------------------------------------------------------------------
-code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_13_1) ->
+code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_17) ->
NewPorts = bump_flex_scanner(Conf),
{ok, State#state{conf = {flex, NewPorts}}};
-code_change(_Vsn, #state{conf = Conf} = State, upgrade_from_pre_3_13_1) ->
+code_change(_Vsn, #state{conf = Conf} = State, upgrade_from_pre_3_17) ->
NewPorts = bump_flex_scanner(Conf),
{ok, State#state{conf = {flex, NewPorts}}};
diff --git a/lib/megaco/test/megaco_appup_test.erl b/lib/megaco/test/megaco_appup_test.erl
index 40eebcae86..fce6cf3cba 100644
--- a/lib/megaco/test/megaco_appup_test.erl
+++ b/lib/megaco/test/megaco_appup_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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
@@ -309,6 +309,9 @@ instruction_module(Instr) ->
%% Check that the modules handled in an instruction set for version X
%% is a subset of the instruction set for version X-1.
check_module_subset(Instructions) ->
+ %% io:format("check_module_subset -> "
+ %% "~n Instructions: ~p"
+ %% "~n", [Instructions]),
do_check_module_subset(modules_of(Instructions)).
do_check_module_subset([]) ->
@@ -316,6 +319,11 @@ do_check_module_subset([]) ->
do_check_module_subset([_]) ->
ok;
do_check_module_subset([{_V1, Mods1}|T]) ->
+ %% io:format("do_check_module_subset -> "
+ %% "~n V1: ~p"
+ %% "~n Mods1: ~p"
+ %% "~n T: ~p"
+ %% "~n", [_V1, Mods1, T]),
{V2, Mods2} = hd(T),
%% Check that the modules in V1 is a subset of V2
case do_check_module_subset2(Mods1, Mods2) of
@@ -347,8 +355,21 @@ modules_of(Instructions) ->
modules_of([], Acc) ->
lists:reverse(Acc);
modules_of([{V,Instructions}|T], Acc) ->
- Mods = modules_of2(Instructions, []),
- modules_of(T, [{V, Mods}|Acc]).
+ %% io:format("modules_of -> "
+ %% "~n V: ~p"
+ %% "~n Instructions: ~p"
+ %% "~n", [V, Instructions]),
+ case modules_of2(Instructions, []) of
+ Mods when is_list(Mods) ->
+ %% io:format("modules_of -> "
+ %% "~n Mods: ~p"
+ %% "~n", [Mods]),
+ modules_of(T, [{V, Mods}|Acc]);
+ skip ->
+ %% io:format("modules_of -> skip"
+ %% "~n", []),
+ modules_of(T, Acc)
+ end.
modules_of2([], Acc) ->
lists:reverse(Acc);
@@ -356,6 +377,8 @@ modules_of2([Instr|Instructions], Acc) ->
case module_of(Instr) of
{value, Mod} ->
modules_of2(Instructions, [Mod|Acc]);
+ skip ->
+ skip;
false ->
modules_of2(Instructions, Acc)
end.
@@ -368,6 +391,8 @@ module_of({load_module, Module, _Pre, _Post, _Depend}) ->
{value, Module};
module_of({update, Module, _Change, _Pre, _Post, _Depend}) ->
{value, Module};
+module_of({restart_application, _App}) ->
+ skip;
module_of(_) ->
false.
diff --git a/lib/megaco/test/megaco_codec_flex_lib.erl b/lib/megaco/test/megaco_codec_flex_lib.erl
index 93bc5d4bbc..3e70454faf 100644
--- a/lib/megaco/test/megaco_codec_flex_lib.erl
+++ b/lib/megaco/test/megaco_codec_flex_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. 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
@@ -49,8 +49,14 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init(Config) when is_list(Config) ->
+ %% io:format("~w:init -> entry with"
+ %% "~n Config: ~p"
+ %% "~n", [?MODULE, Config]),
Flag = process_flag(trap_exit, true),
Res = (catch start()),
+ %% io:format("~w:init -> start result"
+ %% "~n Res: ~p"
+ %% "~n", [?MODULE, Res]),
process_flag(trap_exit, Flag),
case Res of
{error, Reason} ->
diff --git a/lib/megaco/test/megaco_codec_prev3a_test.erl b/lib/megaco/test/megaco_codec_prev3a_test.erl
index b2316eb509..9c4ed385a6 100644
--- a/lib/megaco/test/megaco_codec_prev3a_test.erl
+++ b/lib/megaco/test/megaco_codec_prev3a_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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
@@ -223,23 +223,9 @@ display_text_messages() ->
%% ----
-
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
-
-
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -268,26 +254,34 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
- [{group, text}, {group, binary}, {group, erl_dist},
+ [{group, text},
+ {group, binary},
+ {group, erl_dist},
{group, tickets}].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
{per, [], [per_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
- {group, flex_compact_tickets}, {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, pretty_tickets},
{group, flex_pretty_tickets}]},
{compact_tickets, [],
[compact_otp4011_msg1, compact_otp4011_msg2,
@@ -311,8 +305,7 @@ groups() ->
compact_otp5993_msg01, compact_otp5993_msg02,
compact_otp5993_msg03, compact_otp6017_msg01,
compact_otp6017_msg02, compact_otp6017_msg03]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
{pretty_tickets, [],
[pretty_otp4632_msg1, pretty_otp4632_msg2,
pretty_otp4632_msg3, pretty_otp4632_msg4,
@@ -360,64 +353,61 @@ end_per_group(_GroupName, Config) ->
Config.
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+
flex_compact_tickets_cases() ->
- [flex_compact_otp7431_msg01, flex_compact_otp7431_msg02,
- flex_compact_otp7431_msg03, flex_compact_otp7431_msg04,
- flex_compact_otp7431_msg05, flex_compact_otp7431_msg06,
- flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5085_msg8, flex_pretty_otp5600_msg1,
- flex_pretty_otp5600_msg2, flex_pretty_otp5601_msg1,
- flex_pretty_otp5793_msg01, flex_pretty_otp7431_msg01,
- flex_pretty_otp7431_msg02, flex_pretty_otp7431_msg03,
- flex_pretty_otp7431_msg04, flex_pretty_otp7431_msg05,
- flex_pretty_otp7431_msg06, flex_pretty_otp7431_msg07].
-
-%% ----
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pretty_test_msgs(suite) ->
diff --git a/lib/megaco/test/megaco_codec_prev3b_test.erl b/lib/megaco/test/megaco_codec_prev3b_test.erl
index fa24f49372..36df434e80 100644
--- a/lib/megaco/test/megaco_codec_prev3b_test.erl
+++ b/lib/megaco/test/megaco_codec_prev3b_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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
@@ -241,21 +241,9 @@ generate_text_messages() ->
%% ----
-
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -284,26 +272,36 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
- [{group, text}, {group, binary}, {group, erl_dist},
- {group, tickets}].
+ [
+ {group, text},
+ {group, binary},
+ {group, erl_dist},
+ {group, tickets}
+ ].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
{per, [], [per_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
- {group, flex_compact_tickets}, {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, pretty_tickets},
{group, flex_pretty_tickets}]},
{compact_tickets, [],
[compact_otp4011_msg1, compact_otp4011_msg2,
@@ -328,8 +326,7 @@ groups() ->
compact_otp5993_msg02, compact_otp5993_msg03,
compact_otp6017_msg01, compact_otp6017_msg02,
compact_otp6017_msg03]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
{pretty_tickets, [],
[pretty_otp4632_msg1, pretty_otp4632_msg2,
pretty_otp4632_msg3, pretty_otp4632_msg4,
@@ -379,63 +376,61 @@ end_per_group(_GroupName, Config) ->
Config.
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
flex_compact_tickets_cases() ->
- [flex_compact_otp7431_msg01, flex_compact_otp7431_msg02,
- flex_compact_otp7431_msg03, flex_compact_otp7431_msg04,
- flex_compact_otp7431_msg05, flex_compact_otp7431_msg06,
- flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5085_msg8, flex_pretty_otp5600_msg1,
- flex_pretty_otp5600_msg2, flex_pretty_otp5601_msg1,
- flex_pretty_otp5793_msg01, flex_pretty_otp5803_msg01,
- flex_pretty_otp5803_msg02, flex_pretty_otp5805_msg01,
- flex_pretty_otp5836_msg01, flex_pretty_otp7431_msg01,
- flex_pretty_otp7431_msg02, flex_pretty_otp7431_msg03,
- flex_pretty_otp7431_msg04, flex_pretty_otp7431_msg05,
- flex_pretty_otp7431_msg06, flex_pretty_otp7431_msg07].
-
-%% ----
-
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp5803_msg01,
+ flex_pretty_otp5803_msg02,
+ flex_pretty_otp5805_msg01,
+ flex_pretty_otp5836_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/megaco/test/megaco_codec_prev3c_test.erl b/lib/megaco/test/megaco_codec_prev3c_test.erl
index 7f6d098ed8..3f715cbb7e 100644
--- a/lib/megaco/test/megaco_codec_prev3c_test.erl
+++ b/lib/megaco/test/megaco_codec_prev3c_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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
@@ -247,21 +247,9 @@ generate_text_messages() ->
%% ----
-
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -289,26 +277,36 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
- [{group, text}, {group, binary}, {group, erl_dist},
- {group, tickets}].
+ [
+ {group, text},
+ {group, binary},
+ {group, erl_dist},
+ {group, tickets}
+ ].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
{per, [], [per_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
- {group, flex_compact_tickets}, {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, pretty_tickets},
{group, flex_pretty_tickets}]},
{compact_tickets, [],
[compact_otp4011_msg1, compact_otp4011_msg2,
@@ -332,8 +330,7 @@ groups() ->
compact_otp5993_msg01, compact_otp5993_msg02,
compact_otp5993_msg03, compact_otp6017_msg01,
compact_otp6017_msg02, compact_otp6017_msg03]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
{pretty_tickets, [],
[pretty_otp4632_msg1, pretty_otp4632_msg2,
pretty_otp4632_msg3, pretty_otp4632_msg4,
@@ -383,63 +380,62 @@ end_per_group(_GroupName, Config) ->
Config.
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
-
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+
flex_compact_tickets_cases() ->
- [flex_compact_otp4299_msg1, flex_compact_otp7431_msg01,
- flex_compact_otp7431_msg02, flex_compact_otp7431_msg03,
- flex_compact_otp7431_msg04, flex_compact_otp7431_msg05,
- flex_compact_otp7431_msg06, flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp4299_msg1,
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5085_msg8, flex_pretty_otp5600_msg1,
- flex_pretty_otp5600_msg2, flex_pretty_otp5601_msg1,
- flex_pretty_otp5793_msg01, flex_pretty_otp5803_msg01,
- flex_pretty_otp5803_msg02, flex_pretty_otp5805_msg01,
- flex_pretty_otp5836_msg01, flex_pretty_otp7431_msg01,
- flex_pretty_otp7431_msg02, flex_pretty_otp7431_msg03,
- flex_pretty_otp7431_msg04, flex_pretty_otp7431_msg05,
- flex_pretty_otp7431_msg06, flex_pretty_otp7431_msg07].
-
-%% ----
-
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp5803_msg01,
+ flex_pretty_otp5803_msg02,
+ flex_pretty_otp5805_msg01,
+ flex_pretty_otp5836_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/megaco/test/megaco_codec_v1_test.erl b/lib/megaco/test/megaco_codec_v1_test.erl
index 3be0da3ae4..d1a1d31da0 100644
--- a/lib/megaco/test/megaco_codec_v1_test.erl
+++ b/lib/megaco/test/megaco_codec_v1_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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
@@ -416,20 +416,9 @@ decode_text_messages(Codec, Config, [Msg|Msgs], Acc) ->
%% ----
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -594,61 +583,56 @@ end_per_group(_GroupName, Config) ->
Config.
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6].
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6
+ ].
flex_compact_tickets_cases() ->
- [flex_compact_otp7431_msg01a,
- flex_compact_otp7431_msg01b, flex_compact_otp7431_msg02,
- flex_compact_otp7431_msg03, flex_compact_otp7431_msg04,
- flex_compact_otp7431_msg05, flex_compact_otp7431_msg06,
- flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp7431_msg01a,
+ flex_compact_otp7431_msg01b,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5600_msg1, flex_pretty_otp5600_msg2,
- flex_pretty_otp5601_msg1, flex_pretty_otp5793_msg01,
- flex_pretty_otp7431_msg01, flex_pretty_otp7431_msg02,
- flex_pretty_otp7431_msg03, flex_pretty_otp7431_msg04,
- flex_pretty_otp7431_msg05, flex_pretty_otp7431_msg06,
- flex_pretty_otp7431_msg07].
-
-%% ----
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/megaco/test/megaco_codec_v2_test.erl b/lib/megaco/test/megaco_codec_v2_test.erl
index 1f522504d6..d1fb22cbee 100644
--- a/lib/megaco/test/megaco_codec_v2_test.erl
+++ b/lib/megaco/test/megaco_codec_v2_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,7 +37,8 @@
-export([t/0, t/1]).
--export([all/0,groups/0,init_per_group/2,end_per_group/2,
+-export([all/0,
+ groups/0, init_per_group/2, end_per_group/2,
pretty_test_msgs/1,
@@ -138,7 +139,11 @@
flex_compact_otp7534_msg01/1,
flex_compact_otp7573_msg01/1,
flex_compact_otp7576_msg01/1,
-
+ flex_compact_otp10998_msg01/1,
+ flex_compact_otp10998_msg02/1,
+ flex_compact_otp10998_msg03/1,
+ flex_compact_otp10998_msg04/1,
+
pretty_otp4632_msg1/1,
pretty_otp4632_msg2/1,
pretty_otp4632_msg3/1,
@@ -392,22 +397,10 @@ decode_text_messages(Codec, Config, [Msg|Msgs], Acc) ->
%% ----
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
-
%% ----
@@ -435,79 +428,86 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
-[{group, text}, {group, binary}, {group, erl_dist},
- {group, tickets}].
+ [{group, text},
+ {group, binary},
+ {group, erl_dist},
+ {group, tickets}].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
- {binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
- {erl_dist, [], [{group, erl_dist_m}]},
- {pretty, [], [pretty_test_msgs]},
- {compact, [], [compact_test_msgs]},
- {flex_pretty, [], flex_pretty_cases()},
- {flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
- {per, [], [per_test_msgs]},
- {erl_dist_m, [], [erl_dist_m_test_msgs]},
- {tickets, [],
- [{group, compact_tickets}, {group, pretty_tickets},
- {group, flex_compact_tickets},
- {group, flex_pretty_tickets}]},
- {compact_tickets, [],
- [compact_otp4011_msg1, compact_otp4011_msg2,
- compact_otp4011_msg3, compact_otp4013_msg1,
- compact_otp4085_msg1, compact_otp4085_msg2,
- compact_otp4280_msg1, compact_otp4299_msg1,
- compact_otp4299_msg2, compact_otp4359_msg1,
- compact_otp4920_msg0, compact_otp4920_msg1,
- compact_otp4920_msg2, compact_otp4920_msg3,
- compact_otp4920_msg4, compact_otp4920_msg5,
- compact_otp4920_msg6, compact_otp4920_msg7,
- compact_otp4920_msg8, compact_otp4920_msg9,
- compact_otp4920_msg10, compact_otp4920_msg11,
- compact_otp4920_msg12, compact_otp4920_msg20,
- compact_otp4920_msg21, compact_otp4920_msg22,
- compact_otp4920_msg23, compact_otp4920_msg24,
- compact_otp4920_msg25, compact_otp5186_msg01,
- compact_otp5186_msg02, compact_otp5186_msg03,
- compact_otp5186_msg04, compact_otp5186_msg05,
- compact_otp5186_msg06, compact_otp5290_msg01,
- compact_otp5290_msg02, compact_otp5793_msg01,
- compact_otp5993_msg01, compact_otp5993_msg02,
- compact_otp5993_msg03, compact_otp6017_msg01,
- compact_otp6017_msg02, compact_otp6017_msg03,
- compact_otp7138_msg01, compact_otp7138_msg02,
- compact_otp7457_msg01, compact_otp7457_msg02,
- compact_otp7457_msg03, compact_otp7534_msg01,
- compact_otp7576_msg01, compact_otp7671_msg01]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
- {pretty_tickets, [],
- [pretty_otp4632_msg1, pretty_otp4632_msg2,
- pretty_otp4632_msg3, pretty_otp4632_msg4,
- pretty_otp4710_msg1, pretty_otp4710_msg2,
- pretty_otp4945_msg1, pretty_otp4945_msg2,
- pretty_otp4945_msg3, pretty_otp4945_msg4,
- pretty_otp4945_msg5, pretty_otp4945_msg6,
- pretty_otp4949_msg1, pretty_otp4949_msg2,
- pretty_otp4949_msg3, pretty_otp5042_msg1,
- pretty_otp5068_msg1, pretty_otp5085_msg1,
- pretty_otp5085_msg2, pretty_otp5085_msg3,
- pretty_otp5085_msg4, pretty_otp5085_msg5,
- pretty_otp5085_msg6, pretty_otp5085_msg7,
- pretty_otp5600_msg1, pretty_otp5600_msg2,
- pretty_otp5601_msg1, pretty_otp5793_msg01,
- pretty_otp5882_msg01, pretty_otp6490_msg01,
- pretty_otp6490_msg02, pretty_otp6490_msg03,
- pretty_otp6490_msg04, pretty_otp6490_msg05,
- pretty_otp6490_msg06, pretty_otp7249_msg01,
- pretty_otp7671_msg01, pretty_otp7671_msg02,
- pretty_otp7671_msg03, pretty_otp7671_msg04,
- pretty_otp7671_msg05]},
- {flex_pretty_tickets, [], flex_pretty_tickets_cases()}].
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
+ {binary, [],
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
+ {erl_dist, [], [{group, erl_dist_m}]},
+ {pretty, [], [pretty_test_msgs]},
+ {compact, [], [compact_test_msgs]},
+ {flex_pretty, [], flex_pretty_cases()},
+ {flex_compact, [], flex_compact_cases()},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
+ {per, [], [per_test_msgs]},
+ {erl_dist_m, [], [erl_dist_m_test_msgs]},
+ {tickets, [],
+ [{group, compact_tickets},
+ {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, flex_pretty_tickets}]},
+ {compact_tickets, [],
+ [compact_otp4011_msg1, compact_otp4011_msg2,
+ compact_otp4011_msg3, compact_otp4013_msg1,
+ compact_otp4085_msg1, compact_otp4085_msg2,
+ compact_otp4280_msg1, compact_otp4299_msg1,
+ compact_otp4299_msg2, compact_otp4359_msg1,
+ compact_otp4920_msg0, compact_otp4920_msg1,
+ compact_otp4920_msg2, compact_otp4920_msg3,
+ compact_otp4920_msg4, compact_otp4920_msg5,
+ compact_otp4920_msg6, compact_otp4920_msg7,
+ compact_otp4920_msg8, compact_otp4920_msg9,
+ compact_otp4920_msg10, compact_otp4920_msg11,
+ compact_otp4920_msg12, compact_otp4920_msg20,
+ compact_otp4920_msg21, compact_otp4920_msg22,
+ compact_otp4920_msg23, compact_otp4920_msg24,
+ compact_otp4920_msg25, compact_otp5186_msg01,
+ compact_otp5186_msg02, compact_otp5186_msg03,
+ compact_otp5186_msg04, compact_otp5186_msg05,
+ compact_otp5186_msg06, compact_otp5290_msg01,
+ compact_otp5290_msg02, compact_otp5793_msg01,
+ compact_otp5993_msg01, compact_otp5993_msg02,
+ compact_otp5993_msg03, compact_otp6017_msg01,
+ compact_otp6017_msg02, compact_otp6017_msg03,
+ compact_otp7138_msg01, compact_otp7138_msg02,
+ compact_otp7457_msg01, compact_otp7457_msg02,
+ compact_otp7457_msg03, compact_otp7534_msg01,
+ compact_otp7576_msg01, compact_otp7671_msg01]},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
+ {pretty_tickets, [],
+ [pretty_otp4632_msg1, pretty_otp4632_msg2,
+ pretty_otp4632_msg3, pretty_otp4632_msg4,
+ pretty_otp4710_msg1, pretty_otp4710_msg2,
+ pretty_otp4945_msg1, pretty_otp4945_msg2,
+ pretty_otp4945_msg3, pretty_otp4945_msg4,
+ pretty_otp4945_msg5, pretty_otp4945_msg6,
+ pretty_otp4949_msg1, pretty_otp4949_msg2,
+ pretty_otp4949_msg3, pretty_otp5042_msg1,
+ pretty_otp5068_msg1, pretty_otp5085_msg1,
+ pretty_otp5085_msg2, pretty_otp5085_msg3,
+ pretty_otp5085_msg4, pretty_otp5085_msg5,
+ pretty_otp5085_msg6, pretty_otp5085_msg7,
+ pretty_otp5600_msg1, pretty_otp5600_msg2,
+ pretty_otp5601_msg1, pretty_otp5793_msg01,
+ pretty_otp5882_msg01, pretty_otp6490_msg01,
+ pretty_otp6490_msg02, pretty_otp6490_msg03,
+ pretty_otp6490_msg04, pretty_otp6490_msg05,
+ pretty_otp6490_msg06, pretty_otp7249_msg01,
+ pretty_otp7671_msg01, pretty_otp7671_msg02,
+ pretty_otp7671_msg03, pretty_otp7671_msg04,
+ pretty_otp7671_msg05]},
+ {flex_pretty_tickets, [], flex_pretty_tickets_cases()}].
init_per_group(flex_pretty_tickets, Config) ->
flex_pretty_init(Config);
@@ -533,92 +533,72 @@ end_per_group(_GroupName, Config) ->
-
-
-
-
-
-
-
flex_pretty_cases() ->
-[flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
-[flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-
-
-
-
-
-
-
-
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
-
-
-
-
-
-
-
-flex_compact_tickets_cases() ->
-[flex_compact_otp7138_msg01, flex_compact_otp7138_msg02,
- flex_compact_otp7431_msg01, flex_compact_otp7431_msg02,
- flex_compact_otp7431_msg03, flex_compact_otp7431_msg04,
- flex_compact_otp7431_msg05, flex_compact_otp7431_msg06,
- flex_compact_otp7431_msg07, flex_compact_otp7138_msg02,
- flex_compact_otp7457_msg01, flex_compact_otp7457_msg02,
- flex_compact_otp7457_msg03, flex_compact_otp7534_msg01,
- flex_compact_otp7573_msg01, flex_compact_otp7576_msg01].
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+flex_compact_tickets_cases() ->
+ [
+ flex_compact_otp7138_msg01,
+ flex_compact_otp7138_msg02,
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07,
+ flex_compact_otp7138_msg02,
+ flex_compact_otp7457_msg01,
+ flex_compact_otp7457_msg02,
+ flex_compact_otp7457_msg03,
+ flex_compact_otp7534_msg01,
+ flex_compact_otp7573_msg01,
+ flex_compact_otp7576_msg01,
+ flex_compact_otp10998_msg01,
+ flex_compact_otp10998_msg02,
+ flex_compact_otp10998_msg03,
+ flex_compact_otp10998_msg04
+ ].
flex_pretty_tickets_cases() ->
-[flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5600_msg1, flex_pretty_otp5600_msg2,
- flex_pretty_otp5601_msg1, flex_pretty_otp5793_msg01,
- flex_pretty_otp7431_msg01, flex_pretty_otp7431_msg02,
- flex_pretty_otp7431_msg03, flex_pretty_otp7431_msg04,
- flex_pretty_otp7431_msg05, flex_pretty_otp7431_msg06,
- flex_pretty_otp7431_msg07].
-
-%% ----
-
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
-
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -3138,14 +3118,792 @@ otp7573(Codec, EC, BinMsg) ->
flex_compact_otp7576_msg01(suite) ->
[];
flex_compact_otp7576_msg01(Config) when is_list(Config) ->
-%% put(dbg, true),
-%% put(severity, trc),
+ %% put(dbg, true),
+ %% put(severity, trc),
d("flex_compact_otp7576_msg01 -> entry", []),
Msg = compact_otp7576_msg01(),
Conf = flex_scanner_conf(Config),
compact_otp7576([Conf], Msg).
+%% killer_42_original
+flex_compact_otp10998_msg01() ->
+ <<"!/2 stofmg0
+P=25165898{C=34227581{AV=r01/03/01/38/22{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227613{AV=r01/03/01/38/12{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227744{AV=r01/03/01/38/11{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227755{AV=r01/03/01/38/2{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227768{AV=r01/03/01/38/14{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227774{AV=r01/03/01/38/15{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227775{AV=r01/03/01/38/16{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323119{AV=r01/03/01/38/9{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323122{AV=r01/03/01/38/7{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323156{AV=r01/03/01/38/8{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323260{AV=r01/03/01/38/13{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323272{AV=r01/03/01/38/30{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323273{AV=r01/03/01/38/29{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323275{AV=r01/03/01/38/25{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323276{AV=r01/03/01/38/28{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323279{AV=r01/03/01/38/26{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323280{AV=r01/03/01/38/24{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323281{AV=r01/03/01/38/27{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323284{AV=r01/03/01/38/23{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34129764{AV=r01/03/01/55/31{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227463{AV=r01/03/01/55/26{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227472{AV=r01/03/01/55/22{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227484{AV=r01/03/01/55/16{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227555{AV=r01/03/01/55/5{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227556{AV=r01/03/01/55/14{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227557{AV=r01/03/01/55/10{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227563{AV=r01/03/01/55/7{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227565{AV=r01/03/01/55/13{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227602{AV=r01/03/01/55/21{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227616{AV=r01/03/01/55/1{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227704{AV=r01/03/01/55/19{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227705{AV=r01/03/01/55/18{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227715{AV=r01/03/01/55/20{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322656{AV=r01/03/01/55/30{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322804{AV=r01/03/01/55/24{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322812{AV=r01/03/01/55/15{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322825{AV=r01/03/01/55/4{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322836{AV=r01/03/01/55/17{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323007{AV=r01/03/01/55/6{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323008{AV=r01/03/01/55/2{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323071{AV=r01/03/01/55/28{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323075{AV=r01/03/01/55/29{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}}}">>.
+
+
+%% size36_27_11_bad.txt
+flex_compact_otp10998_msg02() ->
+ <<"!/2 stofmg0
+P=25167656{C=34205358{AV=r01/03/01/27/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34205359{AV=r01/03/01/27/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34205360{AV=r01/03/01/27/23{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227786{AV=r01/03/01/27/8{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230890{AV=r01/03/01/27/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230903{AV=r01/03/01/27/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230904{AV=r01/03/01/27/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230905{AV=r01/03/01/27/12{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230913{AV=r01/03/01/27/4{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316801{AV=r01/03/01/27/9{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316805{AV=r01/03/01/27/19{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316814{AV=r01/03/01/27/5{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316829{AV=r01/03/01/27/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323013{AV=r01/03/01/27/6{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34107499{AV=r01/03/01/11/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34107500{AV=r01/03/01/11/4{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34107505{AV=r01/03/01/11/8{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316766{AV=r01/03/01/11/3{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316768{AV=r01/03/01/11/10{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316786{AV=r01/03/01/11/12{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316787{AV=r01/03/01/11/1{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316793{AV=r01/03/01/11/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316794{AV=r01/03/01/11/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316795{AV=r01/03/01/11/31{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316797{AV=r01/03/01/11/18{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316804{AV=r01/03/01/11/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316807{AV=r01/03/01/11/6{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316815{AV=r01/03/01/11/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316819{AV=r01/03/01/11/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316824{AV=r01/03/01/11/17{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316826{AV=r01/03/01/11/25{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316827{AV=r01/03/01/11/9{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316828{AV=r01/03/01/11/21{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316830{AV=r01/03/01/11/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316832{AV=r01/03/01/11/11{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316850{AV=r01/03/01/11/5{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}}}">>.
+
+
+%% size41_38_55_good.txt
+flex_compact_otp10998_msg03() ->
+ <<"!/2 stofmg0
+P=25166035{C=34227581{AV=r01/03/01/38/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227613{AV=r01/03/01/38/12{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227744{AV=r01/03/01/38/11{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227755{AV=r01/03/01/38/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227768{AV=r01/03/01/38/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227774{AV=r01/03/01/38/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227775{AV=r01/03/01/38/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323122{AV=r01/03/01/38/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323156{AV=r01/03/01/38/8{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323260{AV=r01/03/01/38/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323272{AV=r01/03/01/38/30{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323273{AV=r01/03/01/38/29{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323275{AV=r01/03/01/38/25{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323276{AV=r01/03/01/38/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323279{AV=r01/03/01/38/26{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323280{AV=r01/03/01/38/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323281{AV=r01/03/01/38/27{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323284{AV=r01/03/01/38/23{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34129764{AV=r01/03/01/55/31{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227463{AV=r01/03/01/55/26{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227472{AV=r01/03/01/55/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227484{AV=r01/03/01/55/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227555{AV=r01/03/01/55/5{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227556{AV=r01/03/01/55/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227557{AV=r01/03/01/55/10{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227563{AV=r01/03/01/55/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227565{AV=r01/03/01/55/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227602{AV=r01/03/01/55/21{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227616{AV=r01/03/01/55/1{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227704{AV=r01/03/01/55/19{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227705{AV=r01/03/01/55/18{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227715{AV=r01/03/01/55/20{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322656{AV=r01/03/01/55/30{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322804{AV=r01/03/01/55/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322812{AV=r01/03/01/55/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322825{AV=r01/03/01/55/4{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322836{AV=r01/03/01/55/17{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323007{AV=r01/03/01/55/6{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323008{AV=r01/03/01/55/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323071{AV=r01/03/01/55/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323075{AV=r01/03/01/55/29{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}}}">>.
+
+
+%% size42_38_55_bad.txt
+flex_compact_otp10998_msg04() ->
+ <<"!/2 stofmg0
+P=33555020{C=34227581{AV=r01/03/01/38/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227613{AV=r01/03/01/38/12{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227744{AV=r01/03/01/38/11{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227755{AV=r01/03/01/38/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227768{AV=r01/03/01/38/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227774{AV=r01/03/01/38/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227775{AV=r01/03/01/38/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323119{AV=r01/03/01/38/9{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323122{AV=r01/03/01/38/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323156{AV=r01/03/01/38/8{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323260{AV=r01/03/01/38/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323272{AV=r01/03/01/38/30{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323273{AV=r01/03/01/38/29{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323275{AV=r01/03/01/38/25{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323276{AV=r01/03/01/38/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323279{AV=r01/03/01/38/26{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323280{AV=r01/03/01/38/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323281{AV=r01/03/01/38/27{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323284{AV=r01/03/01/38/23{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34129764{AV=r01/03/01/55/31{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227463{AV=r01/03/01/55/26{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227472{AV=r01/03/01/55/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227484{AV=r01/03/01/55/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227555{AV=r01/03/01/55/5{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227556{AV=r01/03/01/55/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227557{AV=r01/03/01/55/10{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227563{AV=r01/03/01/55/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227565{AV=r01/03/01/55/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227602{AV=r01/03/01/55/21{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227616{AV=r01/03/01/55/1{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227704{AV=r01/03/01/55/19{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227705{AV=r01/03/01/55/18{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227715{AV=r01/03/01/55/20{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322656{AV=r01/03/01/55/30{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322804{AV=r01/03/01/55/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322812{AV=r01/03/01/55/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322825{AV=r01/03/01/55/4{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322836{AV=r01/03/01/55/17{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323007{AV=r01/03/01/55/6{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323008{AV=r01/03/01/55/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323071{AV=r01/03/01/55/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323075{AV=r01/03/01/55/29{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}}}">>.
+
+
+flex_compact_otp10998_num() ->
+ 10.
+
+flex_compact_otp10998_msg01(suite) ->
+ [];
+flex_compact_otp10998_msg01(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp10998_msg01 -> entry", []),
+ Msg = flex_compact_otp10998_msg01(),
+ d("flex_compact_otp10998_msg01 -> message created", []),
+ Conf =
+ try flex_scanner_conf(Config) of
+ C ->
+ C
+ catch
+ exit:Error ->
+ e("Failed getting flex config: "
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end,
+ d("flex_compact_otp10998_msg01 -> flex config generated", []),
+ flex_compact_otp10998([Conf], flex_compact_otp10998_num(), Msg).
+
+flex_compact_otp10998_msg02(suite) ->
+ [];
+flex_compact_otp10998_msg02(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp10998_msg02 -> entry", []),
+ Msg = flex_compact_otp10998_msg02(),
+ d("flex_compact_otp10998_msg02 -> message created", []),
+ Conf =
+ try flex_scanner_conf(Config) of
+ C ->
+ C
+ catch
+ exit:Error ->
+ e("Failed getting flex config: "
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end,
+ d("flex_compact_otp10998_msg02 -> flex config generated", []),
+ flex_compact_otp10998([Conf], flex_compact_otp10998_num(), Msg).
+
+flex_compact_otp10998_msg03(suite) ->
+ [];
+flex_compact_otp10998_msg03(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp10998_msg03 -> entry", []),
+ Msg = flex_compact_otp10998_msg03(),
+ d("flex_compact_otp10998_msg03 -> message created", []),
+ Conf =
+ try flex_scanner_conf(Config) of
+ C ->
+ C
+ catch
+ exit:Error ->
+ e("Failed getting flex config: "
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end,
+ d("flex_compact_otp10998_msg03 -> flex config generated", []),
+ flex_compact_otp10998([Conf], flex_compact_otp10998_num(), Msg).
+
+flex_compact_otp10998_msg04(suite) ->
+ [];
+flex_compact_otp10998_msg04(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp10998_msg04 -> entry", []),
+ Msg = flex_compact_otp10998_msg04(),
+ d("flex_compact_otp10998_msg04 -> message created", []),
+ Conf =
+ try flex_scanner_conf(Config) of
+ C ->
+ C
+ catch
+ exit:Error ->
+ e("Failed getting flex config: "
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end,
+ d("flex_compact_otp10998_msg04 -> flex config generated", []),
+ flex_compact_otp10998([Conf], flex_compact_otp10998_num(), Msg).
+
+flex_compact_otp10998(EC, N, BinMsg) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(No) ->
+ case decode_message(Codec, false, EC, BinMsg) of
+ {ok, _Msg} ->
+ d("flex_compact_otp10998 -> decode ok", []),
+ ok;
+ {error, Reason} ->
+ e("flex_compact_otp10998 -> "
+ "decode ~w failed: ~p", [No, Reason]),
+ throw({error, No, Reason})
+ end
+ end,
+ do_flex_compact_otp10998(N, Decode).
+
+do_flex_compact_otp10998(N, Decode) when N > 0 ->
+ Decode(N),
+ do_flex_compact_otp10998(N-1, Decode);
+do_flex_compact_otp10998(_, _) ->
+ ok.
+
+
+
%% ==============================================================
%%
%% P r e t t y T e s t c a s e s
@@ -6772,7 +7530,14 @@ cre_PkgsItem(Name, Ver) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
flex_init(Config) ->
- megaco_codec_flex_lib:init(Config).
+ %% io:format("~w:flex_init -> entry with: "
+ %% "~n Config: ~p"
+ %% "~n", [?MODULE, Config]),
+ Res = megaco_codec_flex_lib:init(Config),
+ %% io:format("~w:flex_init -> flex init result: "
+ %% "~n Res: ~p"
+ %% "~n", [?MODULE, Res]),
+ Res.
flex_finish(Config) ->
megaco_codec_flex_lib:finish(Config).
diff --git a/lib/megaco/test/megaco_codec_v3_test.erl b/lib/megaco/test/megaco_codec_v3_test.erl
index 9d564a0ae3..84cc863300 100644
--- a/lib/megaco/test/megaco_codec_v3_test.erl
+++ b/lib/megaco/test/megaco_codec_v3_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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
@@ -235,21 +235,9 @@ generate_text_messages() ->
%% ----
-
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -278,26 +266,34 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
- [{group, text}, {group, binary}, {group, erl_dist},
+ [{group, text},
+ {group, binary},
+ {group, erl_dist},
{group, tickets}].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
{per, [], [per_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
- {group, flex_compact_tickets}, {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, pretty_tickets},
{group, flex_pretty_tickets}]},
{compact_tickets, [],
[compact_otp4011_msg1, compact_otp4011_msg2,
@@ -321,8 +317,7 @@ groups() ->
compact_otp5993_msg01, compact_otp5993_msg02,
compact_otp5993_msg03, compact_otp6017_msg01,
compact_otp6017_msg02, compact_otp6017_msg03]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
{pretty_tickets, [],
[pretty_otp4632_msg1, pretty_otp4632_msg2,
pretty_otp4632_msg3, pretty_otp4632_msg4,
@@ -373,69 +368,65 @@ end_per_group(_GroupName, Config) ->
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
-
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
flex_compact_tickets_cases() ->
- [flex_compact_otp4299_msg1, flex_compact_otp7431_msg01,
- flex_compact_otp7431_msg02, flex_compact_otp7431_msg03,
- flex_compact_otp7431_msg04, flex_compact_otp7431_msg05,
- flex_compact_otp7431_msg06, flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp4299_msg1,
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5085_msg8, flex_pretty_otp5600_msg1,
- flex_pretty_otp5600_msg2, flex_pretty_otp5601_msg1,
- flex_pretty_otp5793_msg01, flex_pretty_otp5803_msg01,
- flex_pretty_otp5803_msg02, flex_pretty_otp5805_msg01,
- flex_pretty_otp5836_msg01, flex_pretty_otp7431_msg01,
- flex_pretty_otp7431_msg02, flex_pretty_otp7431_msg03,
- flex_pretty_otp7431_msg04, flex_pretty_otp7431_msg05,
- flex_pretty_otp7431_msg06, flex_pretty_otp7431_msg07].
-
-%% ----
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp5803_msg01,
+ flex_pretty_otp5803_msg02,
+ flex_pretty_otp5805_msg01,
+ flex_pretty_otp5836_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pretty_test_msgs(suite) ->
diff --git a/lib/megaco/test/megaco_test_lib.erl b/lib/megaco/test/megaco_test_lib.erl
index 282fd91b44..41b49f6d30 100644
--- a/lib/megaco/test/megaco_test_lib.erl
+++ b/lib/megaco/test/megaco_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -113,72 +113,17 @@ os_based_skip(_) ->
%% {Mod, Fun, ExpectedRes, ActualRes}
%%----------------------------------------------------------------------
-tickets(Case) ->
- Res = lists:flatten(tickets(Case, default_config())),
- %% io:format("Res: ~p~n", [Res]),
+tickets([Mod]) ->
+ tickets(Mod);
+tickets(Mod) when is_atom(Mod) ->
+ %% p("tickets -> entry with"
+ %% "~n Mod: ~p", [Mod]),
+ Res0 = t({Mod, {group, tickets}, Mod:groups()}, default_config()),
+ Res = lists:flatten(Res0),
+ %% p("tickets(~w) -> Res: ~p~n", [Mod, Res]),
display_result(Res),
Res.
-tickets(Cases, Config) when is_list(Cases) ->
- [tickets(Case, Config) || Case <- Cases];
-tickets(Mod, Config) when is_atom(Mod) ->
- Res = tickets(Mod, tickets, Config),
- Res;
-tickets(Bad, _Config) ->
- [{badarg, Bad, ok}].
-
-tickets(Mod, Func, Config) ->
- case (catch Mod:Func(suite)) of
- [] ->
- io:format("Eval: ~p:", [{Mod, Func}]),
- Res = eval(Mod, Func, Config),
- {R, _, _} = Res,
- io:format(" ~p~n", [R]),
- Res;
-
- Cases when is_list(Cases) ->
- io:format("Expand: ~p:~p ... ~n"
- " ~p~n", [Mod, Func, Cases]),
- Map = fun({M,_}) when is_atom(M) ->
- tickets(M, tickets, Config);
- (F) when is_atom(F) ->
- tickets(Mod, F, Config);
- (Case) -> Case
- end,
- lists:map(Map, Cases);
-
-%% {req, _, {conf, Init, Cases, Finish}} ->
-%% case (catch Mod:Init(Config)) of
-%% Conf when is_list(Conf) ->
-%% io:format("Expand: ~p:~p ...~n", [Mod, Func]),
-%% Map = fun({M,_}) when is_atom(M) ->
-%% tickets(M, tickets, Config);
-%% (F) when is_atom(F) ->
-%% tickets(Mod, F, Config);
-%% (Case) -> Case
-%% end,
-%% Res = lists:map(Map, Cases),
-%% (catch Mod:Finish(Conf)),
-%% Res;
-
-%% {'EXIT', {skipped, Reason}} ->
-%% io:format(" => skipping: ~p~n", [Reason]),
-%% [{skipped, {Mod, Func}, Reason}];
-
-%% Error ->
-%% io:format(" => init failed: ~p~n", [Error]),
-%% [{failed, {Mod, Func}, Error}]
-%% end;
-
- {'EXIT', {undef, _}} ->
- io:format("Undefined: ~p~n", [{Mod, Func}]),
- [{nyi, {Mod, Func}, ok}];
-
- Error ->
- io:format("Ignoring: ~p:~p: ~p~n", [Mod, Func, Error]),
- [{failed, {Mod, Func}, Error}]
- end.
-
display_alloc_info() ->
io:format("Allocator memory information:~n", []),
@@ -254,8 +199,12 @@ alloc_instance_mem_info(Key, InstanceInfo) ->
t([Case]) when is_atom(Case) ->
+ %% p("t -> entry with"
+ %% "~n [Case]: [~p]", [Case]),
t(Case);
t(Case) ->
+ %% p("t -> entry with"
+ %% "~n Case: ~p", [Case]),
process_flag(trap_exit, true),
MEM = fun() -> case (catch erlang:memory()) of
{'EXIT', _} ->
@@ -298,9 +247,16 @@ end_group(Mod, Group, Config) ->
%% This is for sub-SUITEs
t({_Mod, {NewMod, all}, _Groups}, _Config) when is_atom(NewMod) ->
+ %% p("t(all) -> entry with"
+ %% "~n NewMod: ~p", [NewMod]),
t(NewMod);
t({Mod, {group, Name} = Group, Groups}, Config)
when is_atom(Mod) andalso is_atom(Name) andalso is_list(Groups) ->
+ %% p("t(group) -> entry with"
+ %% "~n Mod: ~p"
+ %% "~n Name: ~p"
+ %% "~n Groups: ~p"
+ %% "~n Config: ~p", [Mod, Name, Groups, Config]),
case lists:keysearch(Name, 1, Groups) of
{value, {Name, _Props, GroupsAndCases}} ->
try init_group(Mod, Name, Config) of
@@ -317,7 +273,7 @@ t({Mod, {group, Name} = Group, Groups}, Config)
exit:{skipped, SkipReason} ->
io:format(" => skipping group: ~p~n", [SkipReason]),
[{skipped, {Mod, Group}, SkipReason, 0}];
- exit:{undef, _} ->
+ error:undef ->
[t({Mod, Case, Groups}, Config) ||
Case <- GroupsAndCases];
T:E ->
@@ -328,7 +284,11 @@ t({Mod, {group, Name} = Group, Groups}, Config)
end;
t({Mod, Fun, _}, Config)
when is_atom(Mod) andalso is_atom(Fun) ->
- case catch apply(Mod, Fun, [suite]) of
+ %% p("t -> entry with"
+ %% "~n Mod: ~p"
+ %% "~n Fun: ~p"
+ %% "~n Config: ~p", [Mod, Fun, Config]),
+ try apply(Mod, Fun, [suite]) of
[] ->
io:format("Eval: ~p:", [{Mod, Fun}]),
Res = eval(Mod, Fun, Config),
@@ -343,18 +303,24 @@ t({Mod, Fun, _}, Config)
end,
t(lists:map(Map, Cases), Config);
- {'EXIT', {undef, _}} ->
- io:format("Undefined: ~p~n", [{Mod, Fun}]),
- [{nyi, {Mod, Fun}, ok, 0}];
-
Error ->
io:format("Ignoring: ~p: ~p~n", [{Mod, Fun}, Error]),
[{failed, {Mod, Fun}, Error, 0}]
+
+ catch
+ error:undef ->
+ io:format("Undefined: ~p~n", [{Mod, Fun}]),
+ [{nyi, {Mod, Fun}, ok, 0}]
+
+
end;
t(Mod, Config) when is_atom(Mod) ->
+ %% p("t -> entry with"
+ %% "~n Mod: ~p"
+ %% "~n Config: ~p", [Mod, Config]),
%% This is assumed to be a test suite, so we start by calling
%% the top test suite function(s) (all/0 and groups/0).
- case (catch Mod:all()) of
+ try Mod:all() of
Cases when is_list(Cases) ->
%% The list may contain atoms (actual test cases) and
%% group-tuples (a tuple naming a group of test cases).
@@ -372,17 +338,21 @@ t(Mod, Config) when is_atom(Mod) ->
exit:{skipped, SkipReason} ->
io:format(" => skipping suite: ~p~n", [SkipReason]),
[{skipped, {Mod, init_per_suite}, SkipReason, 0}];
- exit:{undef, _} ->
+ error:undef ->
[t({Mod, Case, Groups}, Config) || Case <- Cases];
T:E ->
+ io:format(" => failed suite: ~p~n", [{T,E}]),
[{failed, {Mod, init_per_suite}, {T,E}, 0}]
end;
- {'EXIT', {undef, _}} ->
- io:format("Undefined: ~p~n", [{Mod, all}]),
- [{nyi, {Mod, all}, ok, 0}];
-
+
Crap ->
Crap
+
+ catch
+ error:undef ->
+ io:format("Undefined: ~p~n", [{Mod, all}]),
+ [{nyi, {Mod, all}, ok, 0}]
+
end;
t(Bad, _Config) ->
[{badarg, Bad, ok, 0}].
@@ -409,6 +379,14 @@ eval(Mod, Fun, Config) ->
wait_for_evaluator(Pid, Mod, Fun, Config, Errors) ->
wait_for_evaluator(Pid, Mod, Fun, Config, Errors, 0).
wait_for_evaluator(Pid, Mod, Fun, Config, Errors, AccTime) ->
+ %% p("wait_for_evaluator -> "
+ %% "~n Pid: ~p"
+ %% "~n Mod: ~p"
+ %% "~n Fun: ~p"
+ %% "~n Config: ~p"
+ %% "~n Errors: ~p"
+ %% "~n AccTime: ~p",
+ %% [Pid, Mod, Fun, Config, Errors, AccTime]),
TestCase = {?MODULE, Mod, Fun},
Label = lists:concat(["TEST CASE: ", Fun]),
receive
@@ -446,16 +424,43 @@ wait_for_evaluator(Pid, Mod, Fun, Config, Errors, AccTime) ->
end.
do_eval(ReplyTo, Mod, Fun, Config) ->
+ %% p("do_eval -> "
+ %% "~n ReplyTo: ~p"
+ %% "~n Mod: ~p"
+ %% "~n Fun: ~p"
+ %% "~n Config: ~p", [ReplyTo, Mod, Fun, Config]),
display_system_info("before", Mod, Fun),
- case timer:tc(Mod, Fun, [Config]) of
- {Time, {'EXIT', {skipped, Reason}}} ->
+ T1 = os:timestamp(),
+ try Mod:Fun(Config) of
+ Res ->
+ %% p("do_eval -> done"
+ %% "~n Res: ~p", [Res]),
+ T2 = os:timestamp(),
+ Time = timer:now_diff(T2, T1),
+ display_tc_time(Time),
+ display_system_info("after", Mod, Fun),
+ ReplyTo ! {done, self(), Res, Time}
+ catch
+ error:undef ->
+ %% p("do_eval -> error - undef", []),
+ ReplyTo ! {'EXIT', self(), undef, 0};
+ exit:{skipped, Reason} ->
+ %% p("do_eval -> exit - skipped"
+ %% "~n Reason: ~p", [Reason]),
+ T2 = os:timestamp(),
+ Time = timer:now_diff(T2, T1),
display_tc_time(Time),
display_system_info("after (skipped)", Mod, Fun),
ReplyTo ! {'EXIT', self(), {skipped, Reason}, Time};
- {Time, Other} ->
+ exit:{suite_failed, Reason} ->
+ %% p("do_eval -> exit - suite-failed"
+ %% "~n Reason: ~p", [Reason]),
+ T2 = os:timestamp(),
+ Time = timer:now_diff(T2, T1),
display_tc_time(Time),
- display_system_info("after", Mod, Fun),
- ReplyTo ! {done, self(), Other, Time}
+ display_system_info("after (failed)", Mod, Fun),
+ ReplyTo ! {done, self(), Reason, Time}
+
end,
unlink(ReplyTo),
exit(shutdown).
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index b61cf2102c..68b12c0286 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = megaco
-MEGACO_VSN = 3.16.0.3
+MEGACO_VSN = 3.17
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)"
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index f9f3ce2ea4..6f9f575d93 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -301,7 +301,13 @@ make_ram_index(Tab, [Pos | Tail]) ->
add_ram_index(Tab, Pos) when is_integer(Pos) ->
verbose("Creating index for ~w ~n", [Tab]),
- Index = mnesia_monitor:mktab(mnesia_index, [bag, public]),
+ SetOrBag = val({Tab, setorbag}),
+ IndexType = case SetOrBag of
+ set -> duplicate_bag;
+ ordered_set -> duplicate_bag;
+ bag -> bag
+ end,
+ Index = mnesia_monitor:mktab(mnesia_index, [IndexType, public]),
Insert = fun(Rec, _Acc) ->
true = ?ets_insert(Index, {element(Pos, Rec), element(2, Rec)})
end,
@@ -309,7 +315,7 @@ add_ram_index(Tab, Pos) when is_integer(Pos) ->
true = ets:foldl(Insert, true, Tab),
mnesia_lib:db_fixtable(ram_copies, Tab, false),
mnesia_lib:set({Tab, {index, Pos}}, Index),
- add_index_info(Tab, val({Tab, setorbag}), {Pos, {ram, Index}});
+ add_index_info(Tab, SetOrBag, {Pos, {ram, Index}});
add_ram_index(_Tab, snmp) ->
ok.
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index 4ba400fbbf..4afbea1cc2 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -487,7 +487,8 @@ finish_copy(Storage,Tab,Cs,SenderPid,DatBin,OrigTabRec) ->
subscr_receiver(TabRef = {_, Tab}, RecName) ->
receive
- {mnesia_table_event, {Op, Val, _Tid}} ->
+ {mnesia_table_event, {Op, Val, _Tid}}
+ when element(1, Val) =:= Tab ->
if
Tab == RecName ->
handle_event(TabRef, Op, Val);
@@ -496,6 +497,15 @@ subscr_receiver(TabRef = {_, Tab}, RecName) ->
end,
subscr_receiver(TabRef, RecName);
+ {mnesia_table_event, {Op, Val, _Tid}} when element(1, Val) =:= schema ->
+ %% clear_table is faked via two schema events
+ %% a schema record delete and a write
+ case Op of
+ delete -> handle_event(TabRef, clear_table, {Tab, all});
+ _ -> ok
+ end,
+ subscr_receiver(TabRef, RecName);
+
{'EXIT', Pid, Reason} ->
handle_exit(Pid, Reason),
subscr_receiver(TabRef, RecName)
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index 64b61288ef..0df245b75d 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -39,7 +39,7 @@ all() ->
db_node_lifecycle, evil_delete_db_node, start_and_stop,
checkpoint, table_lifecycle, storage_options,
add_copy_conflict,
- add_copy_when_going_down, replica_management,
+ add_copy_when_going_down, replica_management, clear_table_during_load,
schema_availability, local_content,
{group, table_access_modifications}, replica_location,
{group, table_sync}, user_properties, unsupp_user_props,
@@ -569,7 +569,50 @@ storage_options(Config) when is_list(Config) ->
?verify_mnesia(Nodes, []).
+clear_table_during_load(suite) -> [];
+clear_table_during_load(doc) ->
+ ["Clear table caused during load caused a schema entry in the actual tab"];
+clear_table_during_load(Config) when is_list(Config) ->
+ Nodes = [_, Node2] = ?acquire_nodes(2, Config ++ [{tc_timeout, timer:minutes(2)}]),
+ ?match({atomic,ok}, mnesia:create_table(cleartab, [{ram_copies, Nodes}])),
+ Tester = self(),
+ Bin = <<"Testingasdasd", 0:32000>>,
+ Fill = fun() -> [mnesia:write({cleartab, N, Bin}) || N <- lists:seq(1, 3000)], ok end,
+ ?match({atomic, ok}, mnesia:sync_transaction(Fill)),
+
+ StopAndStart = fun() ->
+ stopped = mnesia:stop(),
+ Tester ! {self(), stopped},
+ receive start_node -> ok end,
+ ok = mnesia:start(),
+ ok = mnesia:wait_for_tables([cleartab], 2000),
+ lists:foreach(fun({cleartab,_,_}) -> ok;
+ (What) -> Tester ! {failed, What},
+ unlink(Tester),
+ exit(foo)
+ end,
+ ets:tab2list(cleartab)),
+ Tester ! {self(), ok},
+ normal
+ end,
+ Test = fun(N) ->
+ Pid = spawn_link(Node2, StopAndStart),
+ receive {Pid, stopped} -> ok end,
+ Pid ! start_node,
+ timer:sleep(N*10),
+ {atomic, ok} = mnesia:clear_table(cleartab),
+ receive
+ {Pid, ok} -> ok;
+ {failed, What} ->
+ io:format("Failed in ~p tries, with ~p~n",[N, What]),
+ exit({error, What});
+ {'EXIT', Pid, Reason} ->
+ exit({died, Reason})
+ end
+ end,
+ [Test(N) || N <- lists:seq(1, 10)],
+ ?verify_mnesia(Nodes, []).
add_copy_conflict(suite) -> [];
@@ -599,7 +642,7 @@ add_copy_conflict(Config) when is_list(Config) ->
mnesia_controller:unblock_controller(),
?match_receive({test, {atomic,ok}}),
-
+ ?match(ok, mnesia:wait_for_tables([a,b], 3000)),
?verify_mnesia(Nodes, []),
?cleanup(1, Config).
@@ -635,7 +678,7 @@ add_copy_when_going_down(Config) ->
end,
_Lock = spawn(fun() -> mnesia:transaction(WriteAndWait) end),
Tester = self(),
- spawn_link(fun() -> Res = rpc:call(Node2,mnesia, add_table_copy,
+ spawn_link(fun() -> Res = rpc:call(Node2, mnesia, add_table_copy,
[a, Node2, ram_copies]),
Tester ! {test, Res}
end),
diff --git a/lib/orber/src/orber_iiop_outproxy.erl b/lib/orber/src/orber_iiop_outproxy.erl
index 879af8222d..9c4e603753 100644
--- a/lib/orber/src/orber_iiop_outproxy.erl
+++ b/lib/orber/src/orber_iiop_outproxy.erl
@@ -69,13 +69,8 @@ request(Pid, true, Timeout, Msg, RequestId) ->
gen_server:cast(Pid, {request, Timeout, Msg, RequestId, self(), MRef}),
receive
{MRef, Reply} ->
- erlang:demonitor(MRef),
- receive
- {'DOWN', MRef, _, _, _} ->
- Reply
- after 0 ->
- Reply
- end;
+ erlang:demonitor(MRef, [flush]),
+ Reply;
{'DOWN', MRef, _, Pid, _Reason} when is_pid(Pid) ->
receive
%% Clear EXIT message from queue
@@ -444,13 +439,7 @@ collect_fragments(GIOPHdr1, InBuffer, Bytes, Proxy, RequestId, MRef) ->
%% the reply and send it to the client.
{fragment, #giop_message{byte_order = ByteOrder,
message = Message} = GIOPHdr2, RequestId, MRef} ->
- erlang:demonitor(MRef),
- receive
- {'DOWN', MRef, _, _, _} ->
- ok
- after 0 ->
- ok
- end,
+ erlang:demonitor(MRef, [flush]),
case catch cdr_decode:dec_message_header(null, GIOPHdr2, Message) of
{_, #fragment_header{}, FragBody, _, _} ->
%% This buffer is all the fragments concatenated.
@@ -484,13 +473,8 @@ Unable to decode Reply or LocateReply header",[?LINE, NewGIOP, Error], ?DEBUG_LE
{MRef, {'EXCEPTION', E}} ->
orber:dbg("[~p] orber_iiop:collect_fragments(~p);",
[?LINE, E], ?DEBUG_LEVEL),
- erlang:demonitor(MRef),
- receive
- {'DOWN', MRef, _, _, _} ->
- corba:raise(E)
- after 0 ->
- corba:raise(E)
- end;
+ erlang:demonitor(MRef, [flush]),
+ corba:raise(E);
{'DOWN', MRef, _, Proxy, Reason} when is_pid(Proxy) ->
orber:dbg("[~p] orber_iiop:collect_fragments(~p);~n"
"Monitor generated a DOWN message.",
@@ -511,13 +495,8 @@ clear_queue(Proxy, RequestId, MRef) ->
{MRef, RequestId, cancelled} ->
%% This is the last message that the proxy will send
%% after we've cancelled the request.
- erlang:demonitor(MRef),
- receive
- {'DOWN', MRef, _, _, _} ->
- ok
- after 0 ->
- ok
- end;
+ erlang:demonitor(MRef, [flush]),
+ ok;
{'DOWN', MRef, _, Proxy, _Reason} ->
%% The proxy terminated. Clear EXIT message from queue
receive
diff --git a/lib/public_key/asn1/ECPrivateKey.asn1 b/lib/public_key/asn1/ECPrivateKey.asn1
new file mode 100644
index 0000000000..a20fa4009c
--- /dev/null
+++ b/lib/public_key/asn1/ECPrivateKey.asn1
@@ -0,0 +1,24 @@
+ECPrivateKey { iso(1) identified-organization(3) dod(6)
+ internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
+ id-mod-ecprivateKey(65) }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+-- EXPORTS ALL;
+
+IMPORTS
+
+-- FROM New PKIX ASN.1 [RFC5912]
+
+EcpkParameters FROM PKIX1Algorithms88;
+
+ECPrivateKey ::= SEQUENCE {
+ version INTEGER,
+ privateKey OCTET STRING,
+ parameters [0] EcpkParameters OPTIONAL,
+ publicKey [1] BIT STRING OPTIONAL
+}
+
+END
diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1
index a90fe2840c..911a156d6c 100644
--- a/lib/public_key/asn1/OTP-PKIX.asn1
+++ b/lib/public_key/asn1/OTP-PKIX.asn1
@@ -103,15 +103,16 @@ IMPORTS
md5WithRSAEncryption,
sha1WithRSAEncryption,
rsaEncryption, RSAPublicKey,
- dhpublicnumber, DomainParameters, DHPublicKey,
+ dhpublicnumber, DomainParameters, DHPublicKey,
id-keyExchangeAlgorithm, KEA-Parms-Id, --KEA-PublicKey,
- ecdsa-with-SHA1,
+ ecdsa-with-SHA1, ecdsa-with-SHA224,
+ ecdsa-with-SHA256, ecdsa-with-SHA384, ecdsa-with-SHA512,
prime-field, Prime-p,
characteristic-two-field, --Characteristic-two,
gnBasis,
tpBasis, Trinomial,
ppBasis, Pentanomial,
- id-ecPublicKey, EcpkParameters, ECPoint
+ id-ecPublicKey, EcpkParameters, ECParameters, ECPoint
FROM PKIX1Algorithms88 { iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-pkix1-algorithms(17) }
@@ -321,7 +322,11 @@ SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= {
sha256-with-rsa-encryption |
sha384-with-rsa-encryption |
sha512-with-rsa-encryption |
- ecdsa-with-sha1 }
+ ecdsa-with-sha1 |
+ ecdsa-with-sha224 |
+ ecdsa-with-sha256 |
+ ecdsa-with-sha384 |
+ ecdsa-with-sha512 }
SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
dsa | rsa-encryption | dh | kea | ec-public-key }
@@ -439,6 +444,22 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID ecdsa-with-SHA1
TYPE NULL } -- XXX Must be empty and not NULL
+ ecdsa-with-sha224 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA224
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha256 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA256
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha384 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA384
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha512 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA512
+ TYPE NULL } -- XXX Must be empty and not NULL
+
FIELD-ID-CLASS ::= CLASS {
&id OBJECT IDENTIFIER UNIQUE,
&Type }
@@ -489,6 +510,7 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID ppBasis
TYPE Pentanomial }
+
-- SubjectPublicKeyInfo.algorithm
ec-public-key PUBLIC-KEY-ALGORITHM-CLASS ::= {
diff --git a/lib/public_key/asn1/OTP-PUB-KEY.set.asn b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
index f8fb318c93..e94f428e4b 100644
--- a/lib/public_key/asn1/OTP-PUB-KEY.set.asn
+++ b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
@@ -6,5 +6,6 @@ PKIX1Algorithms88.asn1
PKCS-1.asn1
PKCS-3.asn1
DSS.asn1
+ECPrivateKey.asn1
PKCS-7.asn1
PKCS-10.asn1
diff --git a/lib/public_key/asn1/PKCS-1.asn1 b/lib/public_key/asn1/PKCS-1.asn1
index b5754790e7..117eacd8ad 100644
--- a/lib/public_key/asn1/PKCS-1.asn1
+++ b/lib/public_key/asn1/PKCS-1.asn1
@@ -52,8 +52,40 @@ id-md5 OBJECT IDENTIFIER ::= {
iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5
}
+id-hmacWithSHA224 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 8
+}
+
+id-hmacWithSHA256 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 9
+}
+
+id-hmacWithSHA384 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 10
+}
+
+id-hmacWithSHA512 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 11
+}
+
id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 }
+id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 4 }
+
+id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 1 }
+
+id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 2 }
+
+id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 3 }
+
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
diff --git a/lib/public_key/asn1/PKIX1Algorithms88.asn1 b/lib/public_key/asn1/PKIX1Algorithms88.asn1
index 74225747d3..6cc6745af6 100644
--- a/lib/public_key/asn1/PKIX1Algorithms88.asn1
+++ b/lib/public_key/asn1/PKIX1Algorithms88.asn1
@@ -98,6 +98,11 @@
-- OID for ECDSA signatures with SHA-1
ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 }
+ ecdsa-with-SHA2 OBJECT IDENTIFIER ::= { id-ecSigType 3 }
+ ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 1 }
+ ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 2 }
+ ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 3 }
+ ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 4 }
-- OID for an elliptic curve signature
-- format for the value of an ECDSA signature value
@@ -199,40 +204,83 @@
-- Named Elliptic Curves in ANSI X9.62.
- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
-
- c-TwoCurve OBJECT IDENTIFIER ::= {
- ellipticCurve characteristicTwo(0) }
-
- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
-
- primeCurve OBJECT IDENTIFIER ::= { ellipticCurve prime(1) }
-
- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
+ -- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
+
+ -- c-TwoCurve OBJECT IDENTIFIER ::= {
+ -- ansi-ellipticCurve characteristicTwo(0) }
+
+ -- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
+ -- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
+ -- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
+ -- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
+ -- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
+ -- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
+ -- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
+ -- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
+ -- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
+ -- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
+ -- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
+ -- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
+ -- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
+ -- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
+ -- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
+ -- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
+ -- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
+ -- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
+ -- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
+ -- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
+
+ -- primeCurve OBJECT IDENTIFIER ::= { ansi-ellipticCurve prime(1) }
+
+ -- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
+ -- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
+ -- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
+ -- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
+ -- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
+ -- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
+ -- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
+
+ certicom-arc OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132)
+ }
+
+ ellipticCurve OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132) curve(0)
+ }
+
+ secp192r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 1 }
+ secp256r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 7 }
+
+ sect163k1 OBJECT IDENTIFIER ::= { ellipticCurve 1 }
+ sect163r1 OBJECT IDENTIFIER ::= { ellipticCurve 2 }
+ sect239k1 OBJECT IDENTIFIER ::= { ellipticCurve 3 }
+ sect113r1 OBJECT IDENTIFIER ::= { ellipticCurve 4 }
+ sect113r2 OBJECT IDENTIFIER ::= { ellipticCurve 5 }
+ secp112r1 OBJECT IDENTIFIER ::= { ellipticCurve 6 }
+ secp112r2 OBJECT IDENTIFIER ::= { ellipticCurve 7 }
+ secp160r1 OBJECT IDENTIFIER ::= { ellipticCurve 8 }
+ secp160k1 OBJECT IDENTIFIER ::= { ellipticCurve 9 }
+ secp256k1 OBJECT IDENTIFIER ::= { ellipticCurve 10 }
+ sect163r2 OBJECT IDENTIFIER ::= { ellipticCurve 15 }
+ sect283k1 OBJECT IDENTIFIER ::= { ellipticCurve 16 }
+ sect283r1 OBJECT IDENTIFIER ::= { ellipticCurve 17 }
+ sect131r1 OBJECT IDENTIFIER ::= { ellipticCurve 22 }
+ sect131r2 OBJECT IDENTIFIER ::= { ellipticCurve 23 }
+ sect193r1 OBJECT IDENTIFIER ::= { ellipticCurve 24 }
+ sect193r2 OBJECT IDENTIFIER ::= { ellipticCurve 25 }
+ sect233k1 OBJECT IDENTIFIER ::= { ellipticCurve 26 }
+ sect233r1 OBJECT IDENTIFIER ::= { ellipticCurve 27 }
+ secp128r1 OBJECT IDENTIFIER ::= { ellipticCurve 28 }
+ secp128r2 OBJECT IDENTIFIER ::= { ellipticCurve 29 }
+ secp160r2 OBJECT IDENTIFIER ::= { ellipticCurve 30 }
+ secp192k1 OBJECT IDENTIFIER ::= { ellipticCurve 31 }
+ secp224k1 OBJECT IDENTIFIER ::= { ellipticCurve 32 }
+ secp224r1 OBJECT IDENTIFIER ::= { ellipticCurve 33 }
+ secp384r1 OBJECT IDENTIFIER ::= { ellipticCurve 34 }
+ secp521r1 OBJECT IDENTIFIER ::= { ellipticCurve 35 }
+ sect409k1 OBJECT IDENTIFIER ::= { ellipticCurve 36 }
+ sect409r1 OBJECT IDENTIFIER ::= { ellipticCurve 37 }
+ sect571k1 OBJECT IDENTIFIER ::= { ellipticCurve 38 }
+ sect571r1 OBJECT IDENTIFIER ::= { ellipticCurve 39 }
END
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 84300f6e65..10c95a39ac 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -84,7 +84,8 @@
<p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' |
'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo' |
- 'PrivateKeyInfo' | 'CertificationRequest'</code></p>
+ 'PrivateKeyInfo' | 'CertificationRequest' | 'ECPrivateKey'|
+ 'EcpkParameters'</code></p>
<p><code>pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER
not_encrypted | cipher_info()} </code></p>
@@ -99,7 +100,11 @@
<p><code>dsa_public_key() = {integer(), #'Dss-Parms'{}} </code></p>
<p><code>dsa_private_key() = #'DSAPrivateKey'{}</code></p>
+
+ <p><code>ec_public_key() = {#'ECPoint'{}, #'EcpkParameters'{} | {namedCurve, oid()}} </code></p>
+ <p><code>ec_private_key() = #'ECPrivateKey'{}</code></p>
+
<p><code> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </code></p>
<p><code> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
@@ -109,6 +114,8 @@
<p><code> dss_digest_type() = 'sha' </code></p>
+ <p><code> ecdsa_digest_type() = 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512' </code></p>
+
<p><code> crl_reason() = unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise
</code></p>
@@ -147,6 +154,19 @@
<funcs>
<func>
+ <name> compute_key(OthersKey, MyKey)-></name>
+ <name> compute_key(OthersKey, MyKey, Params)-></name>
+ <fsummary> Compute shared secret</fsummary>
+ <type>
+ <v>OthersKey = #'ECPoint'{} | binary(), MyKey = #'ECPrivateKey'{} | binary()</v>
+ <v>Params = #'DHParameter'{}</v>
+ </type>
+ <desc>
+ <p> Compute shared secret </p>
+ </desc>
+ </func>
+
+ <func>
<name>decrypt_private(CipherText, Key) -> binary()</name>
<name>decrypt_private(CipherText, Key, Options) -> binary()</name>
<fsummary>Public key decryption.</fsummary>
@@ -204,6 +224,17 @@
</func>
<func>
+ <name>generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} </name>
+ <fsummary>Generates a new keypair</fsummary>
+ <type>
+ <v> Params = #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} </v>
+ </type>
+ <desc>
+ <p>Generates a new keypair</p>
+ </desc>
+ </func>
+
+ <func>
<name>pem_decode(PemBin) -> [pem_entry()]</name>
<fsummary>Decode PEM binary data and return
entries as ASN.1 DER encoded entities. </fsummary>
@@ -528,8 +559,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<d>The msg is either the binary "plain text" data to be
signed or it is the hashed value of "plain text" i.e. the
digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
- <v>Key = rsa_private_key() | dsa_private_key()</v>
+ <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
+ <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
</type>
<desc>
<p> Creates a digital signature.</p>
@@ -592,12 +623,12 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<v>Msg = binary() | {digest,binary()}</v>
<d>The msg is either the binary "plain text" data
or it is the hashed value of "plain text" i.e. the digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
+ <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
<v>Signature = binary()</v>
- <v>Key = rsa_public_key() | dsa_public_key()</v>
- </type>
- <desc>
- <p>Verifies a digital signature</p>
+ <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
+ </type>
+ <desc>
+ <p>Verifies a digital signature</p>
</desc>
</func>
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index 4d1d510f29..1e882e76ee 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -72,6 +72,10 @@
valid_ext
}).
+-record('ECPoint', {
+ point
+ }).
+
-define(unspecified, 0).
-define(keyCompromise, 1).
@@ -89,6 +93,8 @@
-type rsa_private_key() :: #'RSAPrivateKey'{}.
-type dsa_private_key() :: #'DSAPrivateKey'{}.
-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
+-type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'ECParameters'{}}.
+-type ec_private_key() :: #'ECPrivateKey'{}.
-type der_encoded() :: binary().
-type decrypt_der() :: binary().
-type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey'
diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl
index 98004c71a3..0449129809 100644
--- a/lib/public_key/src/pubkey_cert_records.erl
+++ b/lib/public_key/src/pubkey_cert_records.erl
@@ -23,7 +23,8 @@
-include("public_key.hrl").
--export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1]).
+-export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1,
+ supportedCurvesTypes/1, namedCurves/1]).
%%====================================================================
%% Internal application API
@@ -101,6 +102,77 @@ supportedPublicKeyAlgorithms(?'dhpublicnumber') -> 'DHPublicKey';
supportedPublicKeyAlgorithms(?'id-keyExchangeAlgorithm') -> 'KEA-PublicKey';
supportedPublicKeyAlgorithms(?'id-ecPublicKey') -> 'ECPoint'.
+supportedCurvesTypes(?'characteristic-two-field') -> characteristic_two_field;
+supportedCurvesTypes(?'prime-field') -> prime_field.
+
+namedCurves(?'sect571r1') -> sect571r1;
+namedCurves(?'sect571k1') -> sect571k1;
+namedCurves(?'sect409r1') -> sect409r1;
+namedCurves(?'sect409k1') -> sect409k1;
+namedCurves(?'secp521r1') -> secp521r1;
+namedCurves(?'secp384r1') -> secp384r1;
+namedCurves(?'secp224r1') -> secp224r1;
+namedCurves(?'secp224k1') -> secp224k1;
+namedCurves(?'secp192k1') -> secp192k1;
+namedCurves(?'secp160r2') -> secp160r2;
+namedCurves(?'secp128r2') -> secp128r2;
+namedCurves(?'secp128r1') -> secp128r1;
+namedCurves(?'sect233r1') -> sect233r1;
+namedCurves(?'sect233k1') -> sect233k1;
+namedCurves(?'sect193r2') -> sect193r2;
+namedCurves(?'sect193r1') -> sect193r1;
+namedCurves(?'sect131r2') -> sect131r2;
+namedCurves(?'sect131r1') -> sect131r1;
+namedCurves(?'sect283r1') -> sect283r1;
+namedCurves(?'sect283k1') -> sect283k1;
+namedCurves(?'sect163r2') -> sect163r2;
+namedCurves(?'secp256k1') -> secp256k1;
+namedCurves(?'secp160k1') -> secp160k1;
+namedCurves(?'secp160r1') -> secp160r1;
+namedCurves(?'secp112r2') -> secp112r2;
+namedCurves(?'secp112r1') -> secp112r1;
+namedCurves(?'sect113r2') -> sect113r2;
+namedCurves(?'sect113r1') -> sect113r1;
+namedCurves(?'sect239k1') -> sect239k1;
+namedCurves(?'sect163r1') -> sect163r1;
+namedCurves(?'sect163k1') -> sect163k1;
+namedCurves(?'secp256r1') -> secp256r1;
+namedCurves(?'secp192r1') -> secp192r1;
+
+namedCurves(sect571r1) -> ?'sect571r1';
+namedCurves(sect571k1) -> ?'sect571k1';
+namedCurves(sect409r1) -> ?'sect409r1';
+namedCurves(sect409k1) -> ?'sect409k1';
+namedCurves(secp521r1) -> ?'secp521r1';
+namedCurves(secp384r1) -> ?'secp384r1';
+namedCurves(secp224r1) -> ?'secp224r1';
+namedCurves(secp224k1) -> ?'secp224k1';
+namedCurves(secp192k1) -> ?'secp192k1';
+namedCurves(secp160r2) -> ?'secp160r2';
+namedCurves(secp128r2) -> ?'secp128r2';
+namedCurves(secp128r1) -> ?'secp128r1';
+namedCurves(sect233r1) -> ?'sect233r1';
+namedCurves(sect233k1) -> ?'sect233k1';
+namedCurves(sect193r2) -> ?'sect193r2';
+namedCurves(sect193r1) -> ?'sect193r1';
+namedCurves(sect131r2) -> ?'sect131r2';
+namedCurves(sect131r1) -> ?'sect131r1';
+namedCurves(sect283r1) -> ?'sect283r1';
+namedCurves(sect283k1) -> ?'sect283k1';
+namedCurves(sect163r2) -> ?'sect163r2';
+namedCurves(secp256k1) -> ?'secp256k1';
+namedCurves(secp160k1) -> ?'secp160k1';
+namedCurves(secp160r1) -> ?'secp160r1';
+namedCurves(secp112r2) -> ?'secp112r2';
+namedCurves(secp112r1) -> ?'secp112r1';
+namedCurves(sect113r2) -> ?'sect113r2';
+namedCurves(sect113r1) -> ?'sect113r1';
+namedCurves(sect239k1) -> ?'sect239k1';
+namedCurves(sect163r1) -> ?'sect163r1';
+namedCurves(sect163k1) -> ?'sect163k1';
+namedCurves(secp256r1) -> ?'secp256r1';
+namedCurves(secp192r1) -> ?'secp192r1'.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -111,14 +183,24 @@ decode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
#'PublicKeyAlgorithm'{algorithm=Algo},
subjectPublicKey = {0,SPK0}}) ->
Type = supportedPublicKeyAlgorithms(Algo),
- {ok, SPK} = 'OTP-PUB-KEY':decode(Type, SPK0),
+ SPK = case Type of
+ 'ECPoint' -> #'ECPoint'{point = SPK0};
+ _ -> {ok, SPK1} = 'OTP-PUB-KEY':decode(Type, SPK0),
+ SPK1
+ end,
#'OTPSubjectPublicKeyInfo'{subjectPublicKey = SPK, algorithm=PA}.
encode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
#'PublicKeyAlgorithm'{algorithm=Algo},
subjectPublicKey = SPK0}) ->
Type = supportedPublicKeyAlgorithms(Algo),
- {ok, SPK} = 'OTP-PUB-KEY':encode(Type, SPK0),
+ SPK = case Type of
+ 'ECPoint' ->
+ SPK0#'ECPoint'.point;
+ _ ->
+ {ok, SPK1} = 'OTP-PUB-KEY':encode(Type, SPK0),
+ SPK1
+ end,
#'OTPSubjectPublicKeyInfo'{subjectPublicKey = {0,SPK}, algorithm=PA}.
%%% Extensions
diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl
index 43f6c42f10..6f0be53db9 100644
--- a/lib/public_key/src/pubkey_pbe.erl
+++ b/lib/public_key/src/pubkey_pbe.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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
@@ -23,7 +23,7 @@
-include("public_key.hrl").
-export([encode/4, decode/4, decrypt_parameters/1]).
--export([pbdkdf1/4, pbdkdf2/6]).
+-export([pbdkdf1/4, pbdkdf2/7]).
-define(DEFAULT_SHA_MAC_KEYLEN, 20).
-define(ASN1_OCTET_STR_TAG, 4).
@@ -40,16 +40,16 @@
%%--------------------------------------------------------------------
encode(Data, Password, "DES-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:des_cbc_encrypt(Key, IV, Data);
+ crypto:block_encrypt(des_cbc, Key, IV, Data);
encode(Data, Password, "DES-EDE3-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data);
+ crypto:block_encrypt(des3_cbc, [Key1, Key2, Key3], IV, Data);
encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:rc2_cbc_encrypt(Key, IV, Data).
+ crypto:block_encrypt(rc2_cbc, Key, IV, Data).
%%--------------------------------------------------------------------
-spec decode(binary(), string(), string(), term()) -> binary().
%%
@@ -57,16 +57,16 @@ encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
%%--------------------------------------------------------------------
decode(Data, Password,"DES-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:des_cbc_decrypt(Key, IV, Data);
+ crypto:block_decrypt(des_cbc, Key, IV, Data);
decode(Data, Password,"DES-EDE3-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data);
+ crypto:block_decrypt(des3_cbc, [Key1, Key2, Key3], IV, Data);
decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:rc2_cbc_decrypt(Key, IV, Data).
+ crypto:block_decrypt(rc2_cbc, Key, IV, Data).
%%--------------------------------------------------------------------
-spec pbdkdf1(string(), iodata(), integer(), atom()) -> binary().
@@ -77,21 +77,21 @@ decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) ->
pbdkdf1(_, _, 0, Acc) ->
Acc;
pbdkdf1(Password, Salt, Count, Hash) ->
- Result = crypto:Hash([Password, Salt]),
+ Result = crypto:hash(Hash, [Password, Salt]),
do_pbdkdf1(Result, Count-1, Result, Hash).
%%--------------------------------------------------------------------
--spec pbdkdf2(string(), iodata(), integer(), integer(), fun(), integer())
+-spec pbdkdf2(string(), iodata(), integer(), integer(), fun(), atom(), integer())
-> binary().
%%
%% Description: Implements password based decryption key derive function 2.
%% Exported mainly for testing purposes.
%%--------------------------------------------------------------------
-pbdkdf2(Password, Salt, Count, DerivedKeyLen, Prf, PrfOutputLen)->
+pbdkdf2(Password, Salt, Count, DerivedKeyLen, Prf, PrfHash, PrfOutputLen)->
NumBlocks = ceiling(DerivedKeyLen / PrfOutputLen),
NumLastBlockOctets = DerivedKeyLen - (NumBlocks - 1) * PrfOutputLen ,
blocks(NumBlocks, NumLastBlockOctets, 1, Password, Salt,
- Count, Prf, PrfOutputLen, <<>>).
+ Count, Prf, PrfHash, PrfOutputLen, <<>>).
%%--------------------------------------------------------------------
-spec decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{}) ->
{Cipher::string(), #'PBES2-params'{}}.
@@ -106,10 +106,10 @@ decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{
%%% Internal functions
%%--------------------------------------------------------------------
password_to_key_and_iv(Password, _, #'PBES2-params'{} = Params) ->
- {Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen, IV} =
+ {Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoHash, PseudoOtputLen, IV} =
key_derivation_params(Params),
<<Key:KeyLen/binary, _/binary>> =
- pbdkdf2(Password, Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen),
+ pbdkdf2(Password, Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoHash, PseudoOtputLen),
{Key, IV};
password_to_key_and_iv(Password, Cipher, Salt) ->
KeyLen = derived_key_length(Cipher, undefined),
@@ -122,13 +122,13 @@ password_to_key_and_iv(Password, Cipher, Salt) ->
pem_encrypt(_, _, _, 0, Acc, _) ->
Acc;
pem_encrypt(Prev, Password, Salt, Count, Acc, Hash) ->
- Result = crypto:Hash([Prev, Password, Salt]),
+ Result = crypto:hash(Hash, [Prev, Password, Salt]),
pem_encrypt(Result, Password, Salt, Count-1 , <<Acc/binary, Result/binary>>, Hash).
do_pbdkdf1(_, 0, Acc, _) ->
Acc;
do_pbdkdf1(Prev, Count, Acc, Hash) ->
- Result = crypto:Hash(Prev),
+ Result = crypto:hash(Hash, Prev),
do_pbdkdf1(Result, Count-1 , <<Result/binary, Acc/binary>>, Hash).
iv(#'PBES2-params_encryptionScheme'{algorithm = Algo,
@@ -143,23 +143,23 @@ iv(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC',
{ok, #'RC2-CBC-Parameter'{iv = IV}} = 'PKCS-FRAME':decode('RC2-CBC-Parameter', ASN1IV),
iolist_to_binary(IV).
-blocks(1, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) ->
- <<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfLen),
+blocks(1, N, Index, Password, Salt, Count, Prf, PrfHash, PrfLen, Acc) ->
+ <<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen),
<<Acc/binary, XorSum/binary>>;
-blocks(NumBlocks, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) ->
- XorSum = xor_sum(Password, Salt, Count, Index, Prf, PrfLen),
- blocks(NumBlocks -1, N, Index +1, Password, Salt, Count, Prf,
+blocks(NumBlocks, N, Index, Password, Salt, Count, Prf, PrfHash, PrfLen, Acc) ->
+ XorSum = xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen),
+ blocks(NumBlocks -1, N, Index +1, Password, Salt, Count, Prf, PrfHash,
PrfLen, <<Acc/binary, XorSum/binary>>).
-xor_sum(Password, Salt, Count, Index, Prf, PrfLen) ->
- Result = Prf(Password, [Salt,<<Index:32/unsigned-big-integer>>], PrfLen),
- do_xor_sum(Prf, PrfLen, Result, Password, Count-1, Result).
+xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen) ->
+ Result = Prf(PrfHash, Password, [Salt,<<Index:32/unsigned-big-integer>>], PrfLen),
+ do_xor_sum(Prf, PrfHash, PrfLen, Result, Password, Count-1, Result).
-do_xor_sum(_, _, _, _, 0, Acc) ->
+do_xor_sum(_, _, _, _, _, 0, Acc) ->
Acc;
-do_xor_sum(Prf, PrfLen, Prev, Password, Count, Acc)->
- Result = Prf(Password, Prev, PrfLen),
- do_xor_sum(Prf, PrfLen, Result, Password, Count-1, crypto:exor(Acc, Result)).
+do_xor_sum(Prf, PrfHash, PrfLen, Prev, Password, Count, Acc)->
+ Result = Prf(PrfHash, Password, Prev, PrfLen),
+ do_xor_sum(Prf, PrfHash, PrfLen, Result, Password, Count-1, crypto:exor(Acc, Result)).
decrypt_parameters(?'id-PBES2', DekParams) ->
{ok, Params} = 'PKCS-FRAME':decode('PBES2-params', DekParams),
@@ -174,18 +174,18 @@ key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc,
keyLength = Length,
prf = Prf}} = KeyDerivationFunc,
#'PBES2-params_encryptionScheme'{algorithm = Algo} = EncScheme,
- {PseudoRandomFunction, PseudoOtputLen} = pseudo_random_function(Prf),
+ {PseudoRandomFunction, PseudoHash, PseudoOtputLen} = pseudo_random_function(Prf),
KeyLen = derived_key_length(Algo, Length),
{OctetSalt, Count, KeyLen,
- PseudoRandomFunction, PseudoOtputLen, iv(EncScheme)}.
+ PseudoRandomFunction, PseudoHash, PseudoOtputLen, iv(EncScheme)}.
%% This function currently matches a tuple that ougth to be the value
%% ?'id-hmacWithSHA1, but we need some kind of ASN1-fix for this.
pseudo_random_function(#'PBKDF2-params_prf'{algorithm =
{_,_, _,'id-hmacWithSHA1'}}) ->
- {fun crypto:sha_mac/3, pseudo_output_length(?'id-hmacWithSHA1')};
+ {fun crypto:hmac/4, sha, pseudo_output_length(?'id-hmacWithSHA1')};
pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA1'}) ->
- {fun crypto:sha_mac/3, pseudo_output_length(?'id-hmacWithSHA1')}.
+ {fun crypto:hmac/4, sha, pseudo_output_length(?'id-hmacWithSHA1')}.
pseudo_output_length(?'id-hmacWithSHA1') ->
?DEFAULT_SHA_MAC_KEYLEN.
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index 6bdc35fb79..746d142ec3 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -202,7 +202,11 @@ pem_start('CertificationRequest') ->
pem_start('ContentInfo') ->
<<"-----BEGIN PKCS7-----">>;
pem_start('CertificateList') ->
- <<"-----BEGIN X509 CRL-----">>.
+ <<"-----BEGIN X509 CRL-----">>;
+pem_start('OTPEcpkParameters') ->
+ <<"-----BEGIN EC PARAMETERS-----">>;
+pem_start('ECPrivateKey') ->
+ <<"-----BEGIN EC PRIVATE KEY-----">>.
pem_end(<<"-----BEGIN CERTIFICATE-----">>) ->
<<"-----END CERTIFICATE-----">>;
@@ -226,6 +230,10 @@ pem_end(<<"-----BEGIN PKCS7-----">>) ->
<<"-----END PKCS7-----">>;
pem_end(<<"-----BEGIN X509 CRL-----">>) ->
<<"-----END X509 CRL-----">>;
+pem_end(<<"-----BEGIN EC PARAMETERS-----">>) ->
+ <<"-----END EC PARAMETERS-----">>;
+pem_end(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
+ <<"-----END EC PRIVATE KEY-----">>;
pem_end(_) ->
undefined.
@@ -250,7 +258,11 @@ asn1_type(<<"-----BEGIN CERTIFICATE REQUEST-----">>) ->
asn1_type(<<"-----BEGIN PKCS7-----">>) ->
'ContentInfo';
asn1_type(<<"-----BEGIN X509 CRL-----">>) ->
- 'CertificateList'.
+ 'CertificateList';
+asn1_type(<<"-----BEGIN EC PARAMETERS-----">>) ->
+ 'OTPEcpkParameters';
+asn1_type(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
+ 'ECPrivateKey'.
pem_decrypt() ->
<<"Proc-Type: 4,ENCRYPTED">>.
diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index 008ea96dd3..aed1f57bbc 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -362,18 +362,18 @@ comma_list_encode([Option | Rest], Acc) ->
ssh2_pubkey_encode(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
TypeStr = <<"ssh-rsa">>,
StrLen = size(TypeStr),
- EBin = crypto:mpint(E),
- NBin = crypto:mpint(N),
+ EBin = mpint(E),
+ NBin = mpint(N),
<<?UINT32(StrLen), TypeStr:StrLen/binary,
EBin/binary,
NBin/binary>>;
ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) ->
TypeStr = <<"ssh-dss">>,
StrLen = size(TypeStr),
- PBin = crypto:mpint(P),
- QBin = crypto:mpint(Q),
- GBin = crypto:mpint(G),
- YBin = crypto:mpint(Y),
+ PBin = mpint(P),
+ QBin = mpint(Q),
+ GBin = mpint(G),
+ YBin = mpint(Y),
<<?UINT32(StrLen), TypeStr:StrLen/binary,
PBin/binary,
QBin/binary,
@@ -476,3 +476,32 @@ split_n(N, Bin, Acc) ->
[Last] ->
split_n(0, <<>>, [Last | Acc])
end.
+%% large integer in a binary with 32bit length
+%% MP representaion (SSH2)
+mpint(X) when X < 0 -> mpint_neg(X);
+mpint(X) -> mpint_pos(X).
+
+mpint_neg(X) ->
+ Bin = int_to_bin_neg(X, []),
+ Sz = byte_size(Bin),
+ <<?UINT32(Sz), Bin/binary>>.
+
+mpint_pos(X) ->
+ Bin = int_to_bin_pos(X, []),
+ <<MSB,_/binary>> = Bin,
+ Sz = byte_size(Bin),
+ if MSB band 16#80 == 16#80 ->
+ <<?UINT32((Sz+1)), 0, Bin/binary>>;
+ true ->
+ <<?UINT32(Sz), Bin/binary>>
+ end.
+
+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]).
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 736c18cdd4..3eea6f6ec4 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -35,6 +35,8 @@
encrypt_public/2, encrypt_public/3,
decrypt_public/2, decrypt_public/3,
sign/3, verify/4,
+ generate_key/1,
+ compute_key/2, compute_key/3,
pkix_sign/2, pkix_verify/2,
pkix_sign_types/1,
pkix_is_self_signed/1,
@@ -52,6 +54,7 @@
-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
-type rsa_digest_type() :: 'md5' | 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility
+-type ecdsa_digest_type() :: 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
| cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-type oid() :: tuple().
@@ -94,7 +97,9 @@ pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) ->
der_decode(KeyType, Key0);
'DSAPublicKey' ->
{params, DssParams} = der_decode('DSAParams', Params),
- {der_decode(KeyType, Key0), DssParams}
+ {der_decode(KeyType, Key0), DssParams};
+ 'ECPoint' ->
+ der_decode(KeyType, Key0)
end;
pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
is_binary(Der) ->
@@ -251,10 +256,9 @@ decrypt_private(CipherText,
privateExponent = D} = Key,
Options)
when is_binary(CipherText),
- is_integer(N), is_integer(E), is_integer(D),
is_list(Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_private_decrypt(CipherText, format_rsa_private_key(Key), Padding).
+ crypto:private_decrypt(rsa, CipherText, format_rsa_private_key(Key), Padding).
%%--------------------------------------------------------------------
-spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) ->
@@ -318,30 +322,41 @@ encrypt_private(PlainText,
Options)
when is_binary(PlainText),
is_integer(N), is_integer(E), is_integer(D),
- is_list(Options) ->
+ is_list(Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding).
+ crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), Padding).
+%%--------------------------------------------------------------------
+-spec generate_key(#'DHParameter'{} | {namedCurve, Name ::atom()} |
+ #'ECParameters'{}) -> {Public::binary(), Private::binary()} |
+ #'ECPrivateKey'{}.
+%% Description: Generates a new keypair
+%%--------------------------------------------------------------------
+generate_key(#'DHParameter'{prime = P, base = G}) ->
+ crypto:generate_key(dh, [P, G]);
+generate_key({namedCurve, _} = Params) ->
+ ec_generate_key(Params);
+generate_key(#'ECParameters'{} = Params) ->
+ ec_generate_key(Params).
-format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D,
- prime1 = P1, prime2 = P2,
- exponent1 = E1, exponent2 = E2,
- coefficient = C})
- when is_integer(P1), is_integer(P2),
- is_integer(E1), is_integer(E2), is_integer(C) ->
- [crypto:mpint(K) || K <- [E, N, D, P1, P2, E1, E2, C]];
+%%--------------------------------------------------------------------
+-spec compute_key(#'ECPoint'{} , #'ECPrivateKey'{}) -> binary().
+-spec compute_key(OthersKey ::binary(), MyKey::binary(), #'DHParameter'{}) -> binary().
+%% Description: Compute shared secret
+%%--------------------------------------------------------------------
+compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey,
+ parameters = Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:compute_key(ecdh, Point, list_to_binary(PrivKey), ECCurve).
-format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D}) ->
- [crypto:mpint(K) || K <- [E, N, D]].
+compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) ->
+ crypto:compute_key(dh, PubKey, PrivKey, [P, G]).
%%--------------------------------------------------------------------
-
-spec pkix_sign_types(SignatureAlg::oid()) ->
%% Relevant dsa digest type is subpart of rsa digest type
{ DigestType :: rsa_digest_type(),
- SignatureType :: rsa | dsa
+ SignatureType :: rsa | dsa | ecdsa
}.
%% Description:
%%--------------------------------------------------------------------
@@ -362,68 +377,60 @@ pkix_sign_types(?md5WithRSAEncryption) ->
pkix_sign_types(?'id-dsa-with-sha1') ->
{sha, dsa};
pkix_sign_types(?'id-dsaWithSHA1') ->
- {sha, dsa}.
+ {sha, dsa};
+pkix_sign_types(?'ecdsa-with-SHA1') ->
+ {sha, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA256') ->
+ {sha256, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA384') ->
+ {sha384, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA512') ->
+ {sha512, ecdsa}.
%%--------------------------------------------------------------------
--spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(),
+-spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
rsa_private_key() |
- dsa_private_key()) -> Signature :: binary().
+ dsa_private_key() | ec_private_key()) -> Signature :: binary().
%% Description: Create digital signature.
%%--------------------------------------------------------------------
-sign({digest,_}=Digest, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:rsa_sign(DigestType, Digest, format_rsa_private_key(Key));
+sign(DigestOrPlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
+ crypto:sign(rsa, DigestType, DigestOrPlainText, format_rsa_private_key(Key));
-sign(PlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:rsa_sign(DigestType, sized_binary(PlainText), format_rsa_private_key(Key));
+sign(DigestOrPlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
+ crypto:sign(dss, sha, DigestOrPlainText, [P, Q, G, X]);
-sign({digest,_}=Digest, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(Digest,
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]);
-
-sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(sized_binary(PlainText),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]);
+sign(DigestOrPlainText, DigestType, #'ECPrivateKey'{privateKey = PrivKey,
+ parameters = Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:sign(ecdsa, DigestType, DigestOrPlainText, [list_to_binary(PrivKey), ECCurve]);
%% Backwards compatible
sign(Digest, none, #'DSAPrivateKey'{} = Key) ->
sign({digest,Digest}, sha, Key).
%%--------------------------------------------------------------------
--spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(),
+-spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
Signature :: binary(), rsa_public_key()
- | dsa_public_key()) -> boolean().
+ | dsa_public_key() | ec_public_key()) -> boolean().
%% Description: Verifies a digital signature.
%%--------------------------------------------------------------------
-verify({digest,_}=Digest, DigestType, Signature,
+verify(DigestOrPlainText, DigestType, Signature,
#'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:rsa_verify(DigestType, Digest,
- sized_binary(Signature),
- [crypto:mpint(Exp), crypto:mpint(Mod)]);
+ crypto:verify(rsa, DigestType, DigestOrPlainText, Signature,
+ [Exp, Mod]);
-verify(PlainText, DigestType, Signature,
- #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:rsa_verify(DigestType,
- sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(Exp), crypto:mpint(Mod)]);
+verify(DigestOrPlaintext, DigestType, Signature, {#'ECPoint'{point = Point}, Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, [Point, ECCurve]);
-verify({digest,_}=Digest, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(Signature) ->
- crypto:dss_verify(Digest, sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]);
%% Backwards compatibility
verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) ->
verify({digest,Digest}, sha, Signature, Key);
-verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(PlainText), is_binary(Signature) ->
- crypto:dss_verify(sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]).
+verify(DigestOrPlainText, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
+ when is_integer(Key), is_binary(Signature) ->
+ crypto:verify(dss, DigestType, DigestOrPlainText, Signature, [P, Q, G, Key]).
+
%%--------------------------------------------------------------------
-spec pkix_sign(#'OTPTBSCertificate'{},
rsa_private_key() | dsa_private_key()) -> Der::binary().
@@ -446,7 +453,7 @@ pkix_sign(#'OTPTBSCertificate'{signature =
%%--------------------------------------------------------------------
-spec pkix_verify(Cert::binary(), rsa_public_key()|
- dsa_public_key()) -> boolean().
+ dsa_public_key() | ec_public_key()) -> boolean().
%%
%% Description: Verify pkix x.509 certificate signature.
%%--------------------------------------------------------------------
@@ -458,7 +465,12 @@ pkix_verify(DerCert, {Key, #'Dss-Parms'{}} = DSAKey)
pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey)
when is_binary(DerCert) ->
{DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
- verify(PlainText, DigestType, Signature, RSAKey).
+ verify(PlainText, DigestType, Signature, RSAKey);
+
+pkix_verify(DerCert, Key = {#'ECPoint'{}, _})
+ when is_binary(DerCert) ->
+ {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
+ verify(PlainText, DigestType, Signature, Key).
%%--------------------------------------------------------------------
-spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{} | #'CertificateList'{},
@@ -640,13 +652,11 @@ do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) ->
encrypt_public(PlainText, N, E, Options)->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)],
- Padding).
+ crypto:public_encrypt(rsa, PlainText, [E,N], Padding).
-decrypt_public(CipherText, N,E, Options) ->
+decrypt_public(CipherText, N,E, Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)],
- Padding).
+ crypto:public_decrypt(rsa, CipherText,[E, N], Padding).
path_validation([], #path_validation_state{working_public_key_algorithm
= Algorithm,
@@ -732,10 +742,6 @@ validate(Cert, #path_validation_state{working_issuer_name = Issuer,
pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState).
-sized_binary(Binary) ->
- Size = size(Binary),
- <<?UINT32(Size), Binary/binary>>.
-
otp_cert(Der) when is_binary(Der) ->
pkix_decode_cert(Der, otp);
otp_cert(#'OTPCertificate'{} =Cert) ->
@@ -842,3 +848,38 @@ combine(CRL, DeltaCRLs) ->
end,
lists:foldl(Fun, hd(Deltas), tl(Deltas))
end.
+
+format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
+ privateExponent = D,
+ prime1 = P1, prime2 = P2,
+ exponent1 = E1, exponent2 = E2,
+ coefficient = C})
+ when is_integer(N), is_integer(E), is_integer(D),
+ is_integer(P1), is_integer(P2),
+ is_integer(E1), is_integer(E2), is_integer(C) ->
+ [E, N, D, P1, P2, E1, E2, C];
+
+format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
+ privateExponent = D}) when is_integer(N),
+ is_integer(E),
+ is_integer(D) ->
+ [E, N, D].
+
+ec_generate_key(Params) ->
+ Curve = ec_curve_spec(Params),
+ Term = crypto:generate_key(ecdh, Curve),
+ ec_key(Term, Params).
+
+ec_curve_spec( #'ECParameters'{fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor }) ->
+ Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'FieldID'.fieldType),
+ FieldId#'FieldID'.parameters},
+ Curve = {erlang:list_to_binary(PCurve#'Curve'.a), erlang:list_to_binary(PCurve#'Curve'.b), none},
+ {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor};
+ec_curve_spec({namedCurve, OID}) ->
+ pubkey_cert_records:namedCurves(OID).
+
+ec_key({PubKey, PrivateKey}, Params) ->
+ #'ECPrivateKey'{version = 1,
+ privateKey = binary_to_list(PrivateKey),
+ parameters = Params,
+ publicKey = {0, PubKey}}.
diff --git a/lib/public_key/test/erl_make_certs.erl b/lib/public_key/test/erl_make_certs.erl
index 95e288cd71..5926794ca8 100644
--- a/lib/public_key/test/erl_make_certs.erl
+++ b/lib/public_key/test/erl_make_certs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -234,7 +253,7 @@ extensions(Opts) ->
end.
default_extensions(Exts) ->
- Def = [{key_usage, default},
+ Def = [{key_usage, default},
{subject_altname, undefined},
{issuer_altname, undefined},
{basic_constraints, default},
@@ -248,6 +267,8 @@ default_extensions(Exts) ->
Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end,
Exts ++ lists:foldl(Filter, Def, Exts).
+
+
extension({_, undefined}) -> [];
extension({basic_constraints, Data}) ->
case Data of
@@ -265,11 +286,9 @@ extension({basic_constraints, Data}) ->
#'Extension'{extnID = ?'id-ce-basicConstraints',
extnValue = Data}
end;
-
extension({key_usage, default}) ->
#'Extension'{extnID = ?'id-ce-keyUsage',
extnValue = [keyCertSign], critical = true};
-
extension({Id, Data, Critical}) ->
#'Extension'{extnID = Id, extnValue = Data, critical = Critical}.
@@ -282,7 +301,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -303,13 +329,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -354,24 +391,37 @@ gen_dsa2(LSize, NSize) ->
X0 = prime(LSize),
P0 = prime((LSize div 2) +1),
- %% Choose L-bit prime modulus P such that p–1 is a multiple of q.
+ %% Choose L-bit prime modulus P such that p-1 is a multiple of q.
case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
error ->
gen_dsa2(LSize, NSize);
P ->
- G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
- %% such that This may be done by setting g = h^(p–1)/q mod p, commonly h=2 is used.
+ G = crypto:mod_pow(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
X = prime(20), %% Choose x by some random method, where 0 < x < q.
- Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
+ Y = crypto:mod_pow(G, X, P), %% Calculate y = g^x mod p.
- #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ #'DSAPrivateKey'{version=0, p = P, q = Q,
+ g = crypto:bytes_to_integer(G), y = crypto:bytes_to_integer(Y), x = X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+gen_ec2(CurveId) ->
+ {PubKey, PrivKey} = crypto:generate_key(ecdh, CurveId),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = binary_to_list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
- case is_prime(crypto:mpint(P), 50) of
+ case is_prime(P, 50) of
true -> P;
false -> dsa_search(T+1, P0, Q, Iter-1)
end;
@@ -382,38 +432,40 @@ dsa_search(_,_,_,_) ->
%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime(ByteSize) ->
Rand = odd_rand(ByteSize),
- crypto:erlint(prime_odd(Rand, 0)).
+ prime_odd(Rand, 0).
prime_odd(Rand, N) ->
case is_prime(Rand, 50) of
true ->
Rand;
false ->
- NotPrime = crypto:erlint(Rand),
- prime_odd(crypto:mpint(NotPrime+2), N+1)
+ prime_odd(Rand+2, N+1)
end.
%% see http://en.wikipedia.org/wiki/Fermat_primality_test
is_prime(_, 0) -> true;
is_prime(Candidate, Test) ->
- CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
- case crypto:mod_exp(CoPrime, Candidate, Candidate) of
- CoPrime -> is_prime(Candidate, Test-1);
- _ -> false
- end.
+ CoPrime = odd_rand(10000, Candidate),
+ Result = crypto:mod_pow(CoPrime, Candidate, Candidate) ,
+ is_prime(CoPrime, crypto:bytes_to_integer(Result), Candidate, Test).
+
+is_prime(CoPrime, CoPrime, Candidate, Test) ->
+ is_prime(Candidate, Test-1);
+is_prime(_,_,_,_) ->
+ false.
odd_rand(Size) ->
Min = 1 bsl (Size*8-1),
Max = (1 bsl (Size*8))-1,
- odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+ odd_rand(Min, Max).
odd_rand(Min,Max) ->
- Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
- BitSkip = (Sz+4)*8-1,
- case Rand of
- Odd = <<_:BitSkip, 1:1>> -> Odd;
- Even = <<_:BitSkip, 0:1>> ->
- crypto:mpint(crypto:erlint(Even)+1)
+ Rand = crypto:rand_uniform(Min,Max),
+ case Rand rem 2 of
+ 0 ->
+ Rand + 1;
+ _ ->
+ Rand
end.
extended_gcd(A, B) ->
@@ -432,3 +484,6 @@ pem_to_der(File) ->
der_to_pem(File, Entries) ->
PemBin = public_key:pem_encode(Entries),
file:write_file(File, PemBin).
+
+
+
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 8fba1e8cd3..254601b107 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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
@@ -109,7 +109,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#0c, 16#60, 16#c8, 16#0f, 16#96, 16#1f, 16#0e, 16#71,
16#f3, 16#a9, 16#b5, 16#24, 16#af, 16#60, 16#12, 16#06,
- 16#2f, 16#e0, 16#37, 16#a6>> = pubkey_pbe:pbdkdf2("password", "salt", 1, 20, fun crypto:sha_mac/3, 20),
+ 16#2f, 16#e0, 16#37, 16#a6>> = pubkey_pbe:pbdkdf2("password", "salt", 1, 20, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "password" (8 octets)
@@ -125,7 +125,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#ea, 16#6c, 16#01, 16#4d, 16#c7, 16#2d, 16#6f, 16#8c,
16#cd, 16#1e, 16#d9, 16#2a, 16#ce, 16#1d, 16#41, 16#f0,
16#d8, 16#de, 16#89, 16#57>> =
- pubkey_pbe:pbdkdf2("password", "salt", 2, 20, fun crypto:sha_mac/3, 20),
+ pubkey_pbe:pbdkdf2("password", "salt", 2, 20, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "password" (8 octets)
@@ -140,7 +140,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#4b, 16#00, 16#79, 16#01, 16#b7, 16#65, 16#48, 16#9a,
16#be, 16#ad, 16#49, 16#d9, 16#26, 16#f7, 16#21, 16#d0,
- 16#65, 16#a4, 16#29, 16#c1>> = pubkey_pbe:pbdkdf2("password", "salt", 4096, 20, fun crypto:sha_mac/3, 20),
+ 16#65, 16#a4, 16#29, 16#c1>> = pubkey_pbe:pbdkdf2("password", "salt", 4096, 20, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "password" (8 octets)
@@ -156,7 +156,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#ee, 16#fe, 16#3d, 16#61, 16#cd, 16#4d, 16#a4, 16#e4,
16#e9, 16#94, 16#5b, 16#3d, 16#6b, 16#a2, 16#15, 16#8c,
- 16#26, 16#34, 16#e9, 16#84>> = pubkey_pbe:pbdkdf2("password", "salt", 16777216, 20, fun crypto:sha_mac/3, 20),
+ 16#26, 16#34, 16#e9, 16#84>> = pubkey_pbe:pbdkdf2("password", "salt", 16777216, 20, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "passwordPASSWORDpassword" (24 octets)
@@ -175,7 +175,7 @@ pbdkdf2(Config) when is_list(Config) ->
16#8b, 16#29, 16#1a, 16#96, 16#4c, 16#f2, 16#f0, 16#70,
16#38>>
= pubkey_pbe:pbdkdf2("passwordPASSWORDpassword",
- "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, fun crypto:sha_mac/3, 20),
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "pass\0word" (9 octets)
@@ -190,7 +190,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#56, 16#fa, 16#6a, 16#a7, 16#55, 16#48, 16#09, 16#9d,
16#cc, 16#37, 16#d7, 16#f0, 16#34, 16#25, 16#e0, 16#c3>>
= pubkey_pbe:pbdkdf2("pass\0word",
- "sa\0lt", 4096, 16, fun crypto:sha_mac/3, 20).
+ "sa\0lt", 4096, 16, fun crypto:hmac/4, sha, 20).
encrypted_private_key_info() ->
[{doc,"Tests reading a EncryptedPrivateKeyInfo file encrypted with different ciphers"}].
diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl
index d901adaadd..c490493e13 100644
--- a/lib/public_key/test/pkits_SUITE.erl
+++ b/lib/public_key/test/pkits_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -758,11 +758,12 @@ warning(Format, Args, File0, Line) ->
io:format("~s(~p): Warning "++Format, [File,Line|Args]).
crypto_support_check(Config) ->
- try crypto:sha256(<<"Test">>) of
- _ ->
- Config
- catch error:notsup ->
- crypto:stop(),
+ CryptoSupport = crypto:supports(),
+ Hashs = proplists:get_value(hashs, CryptoSupport),
+ case proplists:get_bool(sha256, Hashs) of
+ true ->
+ Config;
+ false ->
{skip, "To old version of openssl"}
end.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 0de80edeac..5a64140c67 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -551,7 +551,7 @@ dsa_sign_verify(Config) when is_list(Config) ->
false = public_key:verify(Msg, sha, <<1:8, DSASign/binary>>,
{DSAPublicKey, DSAParams}),
- Digest = crypto:sha(Msg),
+ Digest = crypto:hash(sha,Msg),
DigestSign = public_key:sign(Digest, none, DSAPrivateKey),
true = public_key:verify(Digest, none, DigestSign, {DSAPublicKey, DSAParams}),
<<_:8, RestDigest/binary>> = Digest,
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index edccb889b1..9af8f6bae8 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -572,7 +572,7 @@ copy_file(From, To) ->
FromMode = FromInfo#file_info.mode,
ToMode = ToInfo#file_info.mode,
ToMode2 = FromMode bor ToMode,
- FileInfo = FromInfo#file_info{mode = ToMode2},
+ FileInfo = ToInfo#file_info{mode = ToMode2},
write_file_info(To, FileInfo),
ok;
{error, Reason} ->
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index b1e1787f18..752037042d 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -2595,8 +2595,8 @@ start_node(Name, ErlPath, Args0) ->
%io:format("open_port({spawn_executable, ~p}, [{args,~p}])~n",[ErlPath,Args]),
case open_port({spawn_executable, ErlPath}, [{args,Args}]) of
Port when is_port(Port) ->
- unlink(Port),
- erlang:port_close(Port),
+ %% no need to close port since node is detached (see
+ %% mk_node_args) so port will be closed anyway.
case ping_node(FullName, 50) of
ok -> {ok, FullName};
Other -> exit({failed_to_start_node, FullName, Other})
@@ -2629,7 +2629,7 @@ mk_node_args(Name, Args) ->
end,
{ok, Pwd} = file:get_cwd(),
NameStr = atom_to_list(Name),
- ["-detached", "-noinput",
+ ["-detached",
NameSw, NameStr,
"-pa", Pa,
"-env", "ERL_CRASH_DUMP", Pwd ++ "/erl_crash_dump." ++ NameStr,
diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl
index 6e3bfe31c6..6b2fb0460f 100644
--- a/lib/runtime_tools/src/dbg.erl
+++ b/lib/runtime_tools/src/dbg.erl
@@ -551,8 +551,7 @@ c(M, F, A, Flags) ->
stop_clear(),
{error, Reason};
{Pid, Res} ->
- erlang:demonitor(Mref),
- receive {'DOWN', Mref, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
%% 'sleep' prevents the tracer (recv_all_traces) from
%% receiving garbage {'EXIT',...} when dbg i stopped.
timer:sleep(1),
@@ -592,8 +591,7 @@ req(R) ->
{'DOWN', Mref, _, _, _} -> % If server died
exit(dbg_server_crash);
{dbg, Reply} ->
- erlang:demonitor(Mref),
- receive {'DOWN', Mref, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
Reply
end.
diff --git a/lib/runtime_tools/src/ttb_autostart.erl b/lib/runtime_tools/src/ttb_autostart.erl
index 4c6971c119..5339507cec 100644
--- a/lib/runtime_tools/src/ttb_autostart.erl
+++ b/lib/runtime_tools/src/ttb_autostart.erl
@@ -1,3 +1,4 @@
+%%%-*- coding: utf-8 -*-
%%%-------------------------------------------------------------------
%%% File : ttb_autostart.erl
%%% Author : Bartłomiej Puzoń <[email protected]>
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 97ba70c9bd..a56924d5ca 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -1112,10 +1112,10 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
true = rpc:call(Node,erlang,check_old_code,[m10]),
%% Run check_install_release with purge before install this time
- {TCheck,{ok, _RelVsn1, []}} =
+ {_TCheck,{ok, _RelVsn1, []}} =
timer:tc(rpc,call,[Node, release_handler, check_install_release,
[RelVsn2,[purge]]]),
-% ct:log("check_install_release with purge: ~.2f",[TCheck/1000000]),
+% ct:log("check_install_release with purge: ~.2f",[_TCheck/1000000]),
%% Finally install release after check and purge, and check that
%% this install was faster than the first.
@@ -1209,10 +1209,10 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
true = rpc:call(Node,erlang,check_old_code,[m10]),
%% Run check_install_release with purge before install this time
- {TCheck,{ok, _RelVsn1, []}} =
+ {_TCheck,{ok, _RelVsn1, []}} =
timer:tc(rpc,call,[Node, release_handler, check_install_release,
[RelVsn2,[purge]]]),
-% ct:log("check_install_release with purge: ~.2f",[TCheck/1000000]),
+% ct:log("check_install_release with purge: ~.2f",[_TCheck/1000000]),
%% Finally install release after check and purge, and check that
%% this install was faster than the first.
diff --git a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
index 3c4ba1af66..e675cf1b83 100644
--- a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
+++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -214,12 +214,12 @@ check_user(User) ->
case element(?usmUserAuthProtocol, User) of
?usmNoAuthProtocol -> ok;
?usmHMACMD5AuthProtocol ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true -> ok;
false -> exit({unsupported_crypto, md5_mac_96})
end;
?usmHMACSHAAuthProtocol ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true -> ok;
false -> exit({unsupported_crypto, sha_mac_96})
end
@@ -227,14 +227,14 @@ check_user(User) ->
case element(?usmUserPrivProtocol, User) of
?usmNoPrivProtocol -> ok;
?usmDESPrivProtocol ->
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true -> ok;
- false -> exit({unsupported_crypto, des_cbc_decrypt})
+ false -> exit({unsupported_crypto, des_cbc})
end;
?usmAesCfb128Protocol ->
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true -> ok;
- false -> exit({unsupported_crypto, aes_cfb_128_decrypt})
+ false -> exit({unsupported_crypto, aes_cfb128})
end
end.
@@ -874,13 +874,13 @@ validate_auth_protocol(RowIndex, Cols) ->
_ -> inconsistentValue(?usmUserAuthProtocol)
end;
?usmHMACMD5AuthProtocol ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true -> ok;
false ->
wrongValue(?usmUserAuthProtocol)
end;
?usmHMACSHAAuthProtocol ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true -> ok;
false ->
wrongValue(?usmUserAuthProtocol)
@@ -1008,7 +1008,7 @@ validate_priv_protocol(RowIndex, Cols) ->
?usmDESPrivProtocol ->
%% The 'catch' handles the case when 'crypto' is
%% not present in the system.
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true ->
case get_auth_proto(RowIndex, Cols) of
?usmNoAuthProtocol ->
@@ -1022,7 +1022,7 @@ validate_priv_protocol(RowIndex, Cols) ->
?usmAesCfb128Protocol ->
%% The 'catch' handles the case when 'crypto' is
%% not present in the system.
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true ->
case get_auth_proto(RowIndex, Cols) of
?usmNoAuthProtocol ->
@@ -1164,7 +1164,7 @@ mk_key_change(Hash, OldKey, NewKey) ->
%% case in the standard where Random is pre-defined.
mk_key_change(Alg, OldKey, NewKey, KeyLen, Random) ->
%% OldKey and Random is of length KeyLen...
- Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),
+ Digest = lists:sublist(binary_to_list(crypto:hash(Alg, OldKey++Random)), KeyLen),
%% ... and so is Digest
Delta = snmp_misc:str_xor(Digest, NewKey),
Random ++ Delta.
@@ -1181,7 +1181,7 @@ extract_new_key(Hash, OldKey, KeyChange) ->
sha -> sha
end,
{Random, Delta} = split(KeyLen, KeyChange, []),
- Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),
+ Digest = lists:sublist(binary_to_list(crypto:hash(Alg, OldKey++Random)), KeyLen),
NewKey = snmp_misc:str_xor(Digest, Delta),
NewKey.
@@ -1219,10 +1219,13 @@ split(N, [H | T], FirstRev) when N > 0 ->
split(N-1, T, [H | FirstRev]).
-is_crypto_supported(Func) ->
+is_crypto_supported(Algo) ->
%% The 'catch' handles the case when 'crypto' is
%% not present in the system (or not started).
- case catch lists:member(Func, crypto:info()) of
+ Supported = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Supported),
+ Ciphers = proplists:get_value(ciphers, Supported),
+ case catch lists:member(Algo, Hashs ++ Ciphers) of
true -> true;
_ -> false
end.
diff --git a/lib/snmp/src/agent/snmpa_target_cache.erl b/lib/snmp/src/agent/snmpa_target_cache.erl
index 2aa35aa46a..1fcaf82373 100644
--- a/lib/snmp/src/agent/snmpa_target_cache.erl
+++ b/lib/snmp/src/agent/snmpa_target_cache.erl
@@ -21,8 +21,6 @@
-behaviour(gen_server).
%% External exports
-%% Avoid warning for local function demonitor/1 clashing with autoimported BIF.
--compile({no_auto_import,[demonitor/1]}).
-export([start_link/2, stop/0, verbosity/1]).
-export([
@@ -213,21 +211,6 @@ do_init(Prio, Opts) ->
%% requests will have to wait.
%%
-monitor(Pid) -> erlang:monitor(process, Pid).
--ifdef(SNMP_R10).
-demonitor(Ref) ->
- erlang:demonitor(Ref),
- receive
- {_, Ref, _, _, _} ->
- true
- after 0 ->
- true
- end.
--else.
-demonitor(Ref) ->
- erlang:demonitor(Ref, [flush]).
--endif.
-
%% (1) No write_lock active or waiting
handle_call({lock, read = Type, infinity}, {Pid, _} = From,
@@ -236,7 +219,7 @@ handle_call({lock, read = Type, infinity}, {Pid, _} = From,
"entry when no waiting or active writer with"
"~n Pid: ~p"
"~n Cnt: ~p", [Pid, Cnt]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -252,7 +235,7 @@ handle_call({lock, read = Type, infinity}, {Pid, _} = From, State) ->
?vlog("lock(read, infinity) -> "
"entry when active or waiting write locks with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -273,7 +256,7 @@ handle_call({lock, write = Type, infinity}, {Pid, _} = From,
?vlog("lock(write, infinity) -> "
"entry when no active lockers with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -290,7 +273,7 @@ handle_call({lock, write = Type, infinity}, {Pid, _} = From,
?vlog("lock(write, infinity) -> "
"entry when active lockers with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -307,7 +290,7 @@ handle_call({lock, write = Type, infinity}, {Pid, _} = From,
#state{writer = true} = State) ->
?vlog("lock(write, infinity) -> entry with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -429,7 +412,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = read}] ->
?vdebug("unlock -> found read locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
%% ?vtrace("unlock -> done when"
%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
@@ -437,7 +420,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = write}] ->
?vdebug("unlock -> found write locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
%% ?vtrace("unlock -> done when"
%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
@@ -459,7 +442,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = read}] when (Cnt == 1) ->
?vdebug("unlock -> found read locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
case active_waiting_writer(Waiting) of
{true, StillWaiting} ->
@@ -482,7 +465,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = read}] ->
?vdebug("unlock -> found read locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
%% ?vtrace("unlock -> done when"
%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
@@ -492,7 +475,7 @@ handle_cast({unlock, Pid},
%% Release the hord (maybe)
?vdebug("unlock -> found write locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
{Active, StillWaiting, Writer} =
activate_waiting_readers_or_maybe_writer(Waiting),
diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl
index df2c1f0b18..53c291ca0e 100644
--- a/lib/snmp/src/misc/snmp_usm.erl
+++ b/lib/snmp/src/misc/snmp_usm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -69,7 +69,7 @@ passwd2localized_key(Alg, Passwd, EngineID) when length(Passwd) > 0 ->
%%-----------------------------------------------------------------
localize_key(Alg, Key, EngineID) ->
Str = [Key, EngineID, Key],
- binary_to_list(crypto:Alg(Str)).
+ binary_to_list(crypto:hash(Alg, Str)).
mk_digest(md5, Passwd) ->
@@ -78,25 +78,25 @@ mk_digest(sha, Passwd) ->
mk_sha_digest(Passwd).
mk_md5_digest(Passwd) ->
- Ctx = crypto:md5_init(),
+ Ctx = crypto:hash_init(md5),
Ctx2 = md5_loop(0, [], Ctx, Passwd, length(Passwd)),
- crypto:md5_final(Ctx2).
+ crypto:hash_final(Ctx2).
md5_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 ->
{Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen),
- NCtx = crypto:md5_update(Ctx, Buf64),
+ NCtx = crypto:hash_update(Ctx, Buf64),
md5_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen);
md5_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) ->
Ctx.
mk_sha_digest(Passwd) ->
- Ctx = crypto:sha_init(),
+ Ctx = crypto:hash_init(sha),
Ctx2 = sha_loop(0, [], Ctx, Passwd, length(Passwd)),
- crypto:sha_final(Ctx2).
+ crypto:hash_final(Ctx2).
sha_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 ->
{Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen),
- NCtx = crypto:sha_update(Ctx, Buf64),
+ NCtx = crypto:hash_update(Ctx, Buf64),
sha_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen);
sha_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) ->
Ctx.
@@ -147,7 +147,12 @@ md5_auth_out(AuthKey, Message, UsmSecParams) ->
Packet = snmp_pdus:enc_message_only(Message2),
%% 6.3.1.2-4 is done by the crypto function
%% 6.3.1.4
- MAC = binary_to_list(crypto:md5_mac_96(AuthKey, Packet)),
+ MAC = binary_to_list(crypto:hmac(md5, AuthKey, Packet, 12)),
+ ?vtrace("md5_auth_out -> entry with"
+ "~n Packet: ~w"
+ "~n AuthKey: ~w"
+ "~n MAC: ~w"
+ , [Packet, AuthKey, MAC]),
%% 6.3.1.5
set_msg_auth_params(Message, UsmSecParams, MAC).
@@ -155,13 +160,14 @@ md5_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) == 12 ->
%% 6.3.2.3
Packet2 = patch_packet(binary_to_list(Packet)),
%% 6.3.2.5
- MAC = binary_to_list(crypto:md5_mac_96(AuthKey, Packet2)),
+ MAC = binary_to_list(crypto:hmac(md5, AuthKey, Packet2, 12)),
%% 6.3.2.6
-%% ?vtrace("md5_auth_in -> entry with"
-%% "~n Packet2: ~w"
-%% "~n AuthKey: ~w"
-%% "~n AuthParams: ~w"
-%% "~n MAC: ~w", [Packet2, AuthKey, AuthParams, MAC]),
+ ?vtrace("md5_auth_in -> entry with"
+ "~n Packet2: ~w"
+ "~n AuthKey: ~w"
+ "~n AuthParams: ~w"
+ "~n MAC: ~w"
+ , [Packet2, AuthKey, AuthParams, MAC]),
MAC == AuthParams;
md5_auth_in(_AuthKey, _AuthParams, _Packet) ->
%% 6.3.2.1
@@ -177,7 +183,7 @@ sha_auth_out(AuthKey, Message, UsmSecParams) ->
Packet = snmp_pdus:enc_message_only(Message2),
%% 7.3.1.2-4 is done by the crypto function
%% 7.3.1.4
- MAC = binary_to_list(crypto:sha_mac_96(AuthKey, Packet)),
+ MAC = binary_to_list(crypto:hmac(sha, AuthKey, Packet, 12)),
%% 7.3.1.5
set_msg_auth_params(Message, UsmSecParams, MAC).
@@ -185,7 +191,7 @@ sha_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) =:= 12 ->
%% 7.3.2.3
Packet2 = patch_packet(binary_to_list(Packet)),
%% 7.3.2.5
- MAC = binary_to_list(crypto:sha_mac_96(AuthKey, Packet2)),
+ MAC = binary_to_list(crypto:hmac(sha, AuthKey, Packet2, 12)),
%% 7.3.2.6
MAC == AuthParams;
sha_auth_in(_AuthKey, _AuthParams, _Packet) ->
@@ -203,7 +209,7 @@ des_encrypt(PrivKey, Data, SaltFun) ->
IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)),
TailLen = (8 - (length(Data) rem 8)) rem 8,
Tail = mk_tail(TailLen),
- EncData = crypto:des_cbc_encrypt(DesKey, IV, [Data,Tail]),
+ EncData = crypto:block_encrypt(des_cbc, DesKey, IV, [Data,Tail]),
{ok, binary_to_list(EncData), Salt}.
des_decrypt(PrivKey, MsgPrivParams, EncData)
@@ -217,7 +223,7 @@ des_decrypt(PrivKey, MsgPrivParams, EncData)
Salt = MsgPrivParams,
IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)),
%% Whatabout errors here??? E.g. not a mulitple of 8!
- Data = binary_to_list(crypto:des_cbc_decrypt(DesKey, IV, EncData)),
+ Data = binary_to_list(crypto:block_decrypt(des_cbc, DesKey, IV, EncData)),
Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data),
{ok, Data2};
des_decrypt(PrivKey, BadMsgPrivParams, EncData) ->
@@ -235,7 +241,7 @@ aes_encrypt(PrivKey, Data, SaltFun) ->
EngineBoots = snmp_framework_mib:get_engine_boots(),
EngineTime = snmp_framework_mib:get_engine_time(),
IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]),
- EncData = crypto:aes_cfb_128_encrypt(AesKey, IV, Data),
+ EncData = crypto:block_encrypt(aes_cbf128, AesKey, IV, Data),
{ok, binary_to_list(EncData), Salt}.
aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime)
@@ -244,7 +250,7 @@ aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime)
Salt = MsgPrivParams,
IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]),
%% Whatabout errors here??? E.g. not a mulitple of 8!
- Data = binary_to_list(crypto:aes_cfb_128_decrypt(AesKey, IV, EncData)),
+ Data = binary_to_list(crypto:block_decrypt(aes_cbf128, AesKey, IV, EncData)),
Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data),
{ok, Data2}.
diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index 5841f06d70..fc6efc817f 100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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
@@ -33,7 +33,6 @@
%% integer utils
-export([isize/1]).
--export([irandom/1, irandom/3]).
-export([random/1]).
-export([xor_bits/2, fill_bits/2]).
-export([i2bin/2, bin2i/1]).
@@ -387,31 +386,7 @@ xor_bits(XBits, YBits) ->
<<Y:Sz, _/binary>> = YBits,
<<(X bxor Y):Sz>>.
-%%
-%% irandom(N)
-%%
-%% Generate a N bits size random number
-%% note that the top most bit is always set
-%% to guarantee that the number is N bits
-%%
-irandom(Bits) ->
- irandom(Bits, 1, 0).
-
-%%
-%% irandom(N, Top, Bottom)
-%%
-%% Generate a N bits size random number
-%% Where Top = 0 - do not set top bit
-%% = 1 - set the most significant bit
-%% = 2 - set two most significant bits
-%% Bot = 0 - do not set the least signifcant bit
-%% Bot = 1 - set the least signifcant bit (i.e always odd)
-%%
-irandom(Bits, Top, Bottom) when is_integer(Top),
- 0 =< Top, Top =< 2 ->
- crypto:erlint(crypto:strong_rand_mpint(Bits, Top - 1, Bottom)).
-%%
%% random/1
%% Generate N random bytes
%%
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 0531ad7830..69b1ab186f 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -230,11 +230,11 @@ io_request({window_change, OldTty}, Buf, Tty) ->
io_request({put_chars, Cs}, Buf, Tty) ->
put_chars(bin_to_list(Cs), Buf, Tty);
io_request({put_chars, unicode, Cs}, Buf, Tty) ->
- put_chars([Ch || Ch <- unicode:characters_to_list(Cs,unicode), Ch =< 255], Buf, Tty);
+ put_chars(unicode:characters_to_list(Cs,unicode), Buf, Tty);
io_request({insert_chars, Cs}, Buf, Tty) ->
insert_chars(bin_to_list(Cs), Buf, Tty);
io_request({insert_chars, unicode, Cs}, Buf, Tty) ->
- insert_chars([Ch || Ch <- unicode:characters_to_list(Cs,unicode), Ch =< 255], Buf, Tty);
+ insert_chars(unicode:characters_to_list(Cs,unicode), Buf, Tty);
io_request({move_rel, N}, Buf, Tty) ->
move_rel(N, Buf, Tty);
io_request({delete_chars,N}, Buf, Tty) ->
diff --git a/lib/ssh/src/ssh_math.erl b/lib/ssh/src/ssh_math.erl
index 4aa385b18d..569c1cb58d 100644
--- a/lib/ssh/src/ssh_math.erl
+++ b/lib/ssh/src/ssh_math.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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
@@ -23,109 +23,19 @@
-module(ssh_math).
--export([ilog2/1, ipow/3, invert/2, ipow2/3]).
+-export([ipow/3]).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% INTEGER utils
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% number of bits (used) in a integer = isize(N) = |log2(N)|+1
-ilog2(N) ->
- ssh_bits:isize(N) - 1.
-
-
%% calculate A^B mod M
ipow(A, B, M) when M > 0, B >= 0 ->
- crypto:mod_exp(A, B, M).
-
-ipow2(A, B, M) when M > 0, B >= 0 ->
- if A == 1 ->
- 1;
- true ->
- ipow2(A, B, M, 1)
- end.
-
-ipow2(A, 1, M, Prod) ->
- (A*Prod) rem M;
-ipow2(_A, 0, _M, Prod) ->
- Prod;
-ipow2(A, B, M, Prod) ->
- B1 = B bsr 1,
- A1 = (A*A) rem M,
- if B - B1 == B1 ->
- ipow2(A1, B1, M, Prod);
- true ->
- ipow2(A1, B1, M, (A*Prod) rem M)
- end.
-
-%% %%
-%% %% Normal gcd
-%% %%
-%% gcd(R, Q) when abs(Q) < abs(R) -> gcd1(Q,R);
-%% gcd(R, Q) -> gcd1(R,Q).
-
-%% gcd1(0, Q) -> Q;
-%% gcd1(R, Q) ->
-%% gcd1(Q rem R, R).
-
-
-%% %%
-%% %% Least common multiple of (R,Q)
-%% %%
-%% lcm(0, _Q) -> 0;
-%% lcm(_R, 0) -> 0;
-%% lcm(R, Q) ->
-%% (Q div gcd(R, Q)) * R.
-
-%% %%
-%% %% Extended gcd gcd(R,Q) -> {G, {A,B}} such that G == R*A + Q*B
-%% %%
-%% %% Here we could have use for a bif divrem(Q, R) -> {Quote, Remainder}
-%% %%
-%% egcd(R,Q) when abs(Q) < abs(R) -> egcd1(Q,R,1,0,0,1);
-%% egcd(R,Q) -> egcd1(R,Q,0,1,1,0).
-
-%% egcd1(0,Q,_,_,Q1,Q2) -> {Q, {Q2,Q1}};
-%% egcd1(R,Q,R1,R2,Q1,Q2) ->
-%% D = Q div R,
-%% egcd1(Q rem R, R, Q1-D*R1, Q2-D*R2, R1, R2).
-
-%%
-%% Invert an element X mod P
-%% Calculated as {1, {A,B}} = egcd(X,P),
-%% 1 == P*A + X*B == X*B (mod P) i.e B is the inverse element
-%%
-%% X > 0, P > 0, X < P (P should be prime)
-%%
-invert(X,P) when X > 0, P > 0, X < P ->
- I = inv(X,P,1,0),
- if
- I < 0 -> P + I;
- true -> I
- end.
-
-inv(0,_,_,Q) -> Q;
-inv(X,P,R1,Q1) ->
- D = P div X,
- inv(P rem X, X, Q1 - D*R1, R1).
-
+ crypto:bytes_to_integer(crypto:mod_pow(A, B, M)).
-%% %%
-%% %% Integer square root
-%% %%
-%% isqrt(0) -> 0;
-%% isqrt(1) -> 1;
-%% isqrt(X) when X >= 0 ->
-%% R = X div 2,
-%% isqrt(X div R, R, X).
-%% isqrt(Q,R,X) when Q < R ->
-%% R1 = (R+Q) div 2,
-%% isqrt(X div R1, R1, X);
-%% isqrt(_, R, _) -> R.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 98d59d01de..beaffdc025 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -792,14 +792,14 @@ encrypt(#ssh{encrypt = none} = Ssh, Data) ->
encrypt(#ssh{encrypt = '3des-cbc',
encrypt_keys = {K1,K2,K3},
encrypt_ctx = IV0} = Ssh, Data) ->
- Enc = crypto:des3_cbc_encrypt(K1,K2,K3,IV0,Data),
- IV = crypto:des_cbc_ivec(Enc),
+ Enc = crypto:block_encrypt(des3_cbc, [K1,K2,K3], IV0, Data),
+ IV = crypto:next_iv(des3_cbc, Enc),
{Ssh#ssh{encrypt_ctx = IV}, Enc};
encrypt(#ssh{encrypt = 'aes128-cbc',
encrypt_keys = K,
encrypt_ctx = IV0} = Ssh, Data) ->
- Enc = crypto:aes_cbc_128_encrypt(K,IV0,Data),
- IV = crypto:aes_cbc_ivec(Enc),
+ Enc = crypto:block_encrypt(aes_cbc128, K,IV0,Data),
+ IV = crypto:next_iv(aes_cbc, Enc),
{Ssh#ssh{encrypt_ctx = IV}, Enc}.
@@ -846,13 +846,13 @@ decrypt(#ssh{decrypt = none} = Ssh, Data) ->
decrypt(#ssh{decrypt = '3des-cbc', decrypt_keys = Keys,
decrypt_ctx = IV0} = Ssh, Data) ->
{K1, K2, K3} = Keys,
- Dec = crypto:des3_cbc_decrypt(K1,K2,K3,IV0,Data),
- IV = crypto:des_cbc_ivec(Data),
+ Dec = crypto:block_decrypt(des3_cbc, [K1,K2,K3], IV0, Data),
+ IV = crypto:next_iv(des3_cbc, Data),
{Ssh#ssh{decrypt_ctx = IV}, Dec};
decrypt(#ssh{decrypt = 'aes128-cbc', decrypt_keys = Key,
decrypt_ctx = IV0} = Ssh, Data) ->
- Dec = crypto:aes_cbc_128_decrypt(Key,IV0,Data),
- IV = crypto:aes_cbc_ivec(Data),
+ Dec = crypto:block_decrypt(aes_cbc128, Key,IV0,Data),
+ IV = crypto:next_iv(aes_cbc, Data),
{Ssh#ssh{decrypt_ctx = IV}, Dec}.
@@ -954,22 +954,22 @@ recv_mac_final(SSH) ->
mac(none, _ , _, _) ->
<<>>;
mac('hmac-sha1', Key, SeqNum, Data) ->
- crypto:sha_mac(Key, [<<?UINT32(SeqNum)>>, Data]);
+ crypto:hmac(sha, Key, [<<?UINT32(SeqNum)>>, Data]);
mac('hmac-sha1-96', Key, SeqNum, Data) ->
- crypto:sha_mac_96(Key, [<<?UINT32(SeqNum)>>, Data]);
+ crypto:hmac(sha, Key, [<<?UINT32(SeqNum)>>, Data], mac_digest_size('hmac-sha1-96'));
mac('hmac-md5', Key, SeqNum, Data) ->
- crypto:md5_mac(Key, [<<?UINT32(SeqNum)>>, Data]);
+ crypto:hmac(md5, Key, [<<?UINT32(SeqNum)>>, Data]);
mac('hmac-md5-96', Key, SeqNum, Data) ->
- crypto:md5_mac_96(Key, [<<?UINT32(SeqNum)>>, Data]).
+ crypto:hmac(md5, Key, [<<?UINT32(SeqNum)>>, Data], mac_digest_size('hmac-md5-96')).
%% return N hash bytes (HASH)
hash(SSH, Char, Bits) ->
HASH =
case SSH#ssh.kex of
'diffie-hellman-group1-sha1' ->
- fun(Data) -> crypto:sha(Data) end;
+ fun(Data) -> crypto:hash(sha, Data) end;
'diffie-hellman-group-exchange-sha1' ->
- fun(Data) -> crypto:sha(Data) end;
+ fun(Data) -> crypto:hash(sha, Data) end;
_ ->
exit({bad_algorithm,SSH#ssh.kex})
end,
@@ -998,7 +998,7 @@ kex_h(SSH, K_S, E, F, K) ->
K_S, E,F,K],
[string,string,binary,binary,binary,
mpint,mpint,mpint]),
- crypto:sha(L).
+ crypto:hash(sha,L).
kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
@@ -1019,7 +1019,7 @@ kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
K_S, Min, NBits, Max,
Prime, Gen, E,F,K], Ts)
end,
- crypto:sha(L).
+ crypto:hash(sha,L).
mac_key_size('hmac-sha1') -> 20*8;
mac_key_size('hmac-sha1-96') -> 20*8;
@@ -1045,10 +1045,9 @@ peer_name({Host, _}) ->
dh_group1() ->
{2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF}.
-dh_gen_key(G, P, _Bits) ->
- Private = ssh_bits:irandom(ssh_bits:isize(P)-1, 1, 1),
- Public = ssh_math:ipow(G, Private, P),
- {Private,Public}.
+dh_gen_key(G, P, _) ->
+ {Public, Private} = crypto:generate_key(dh, [P, G]),
+ {crypto:bytes_to_integer(Private), crypto:bytes_to_integer(Public)}.
trim_tail(Str) ->
lists:reverse(trim_head(lists:reverse(Str))).
@@ -1058,3 +1057,5 @@ trim_head([$\t|Cs]) -> trim_head(Cs);
trim_head([$\n|Cs]) -> trim_head(Cs);
trim_head([$\r|Cs]) -> trim_head(Cs);
trim_head(Cs) -> Cs.
+
+
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index 4dfd9ed8b0..93f9e20663 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -72,7 +72,7 @@ protocol_version_request(XF) ->
open(XF, ReqID, FileName, Access, Flags, Attrs) ->
Vsn = XF#ssh_xfer.vsn,
- FileName1 = list_to_binary(FileName),
+ FileName1 = unicode:characters_to_binary(FileName),
MBits = if Vsn >= 5 ->
M = encode_ace_mask(Access),
?uint32(M);
@@ -115,7 +115,7 @@ write(XF,ReqID, Handle, Offset, Data) ->
is_binary(Data) ->
Data;
is_list(Data) ->
- list_to_binary(Data)
+ unicode:characters_to_binary(Data)
end,
xf_request(XF,?SSH_FXP_WRITE,
[?uint32(ReqID),
@@ -132,8 +132,8 @@ remove(XF, ReqID, File) ->
%% Rename a file/directory
rename(XF, ReqID, Old, New, Flags) ->
Vsn = XF#ssh_xfer.vsn,
- OldPath = list_to_binary(Old),
- NewPath = list_to_binary(New),
+ OldPath = unicode:characters_to_binary(Old),
+ NewPath = unicode:characters_to_binary(New),
FlagBits
= if Vsn >= 5 ->
F0 = encode_rename_flags(Flags),
@@ -151,7 +151,7 @@ rename(XF, ReqID, Old, New, Flags) ->
%% Create directory
mkdir(XF, ReqID, Path, Attrs) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
xf_request(XF, ?SSH_FXP_MKDIR,
[?uint32(ReqID),
?binary(Path1),
@@ -159,14 +159,14 @@ mkdir(XF, ReqID, Path, Attrs) ->
%% Remove a directory
rmdir(XF, ReqID, Dir) ->
- Dir1 = list_to_binary(Dir),
+ Dir1 = unicode:characters_to_binary(Dir),
xf_request(XF, ?SSH_FXP_RMDIR,
[?uint32(ReqID),
?binary(Dir1)]).
%% Stat file
stat(XF, ReqID, Path, Flags) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
Vsn = XF#ssh_xfer.vsn,
AttrFlags = if Vsn >= 5 ->
F = encode_attr_flags(Vsn, Flags),
@@ -182,7 +182,7 @@ stat(XF, ReqID, Path, Flags) ->
%% Stat file - follow symbolic links
lstat(XF, ReqID, Path, Flags) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
Vsn = XF#ssh_xfer.vsn,
AttrFlags = if Vsn >= 5 ->
F = encode_attr_flags(Vsn, Flags),
@@ -211,7 +211,7 @@ fstat(XF, ReqID, Handle, Flags) ->
%% Modify file attributes
setstat(XF, ReqID, Path, Attrs) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
xf_request(XF, ?SSH_FXP_SETSTAT,
[?uint32(ReqID),
?binary(Path1),
@@ -227,7 +227,7 @@ fsetstat(XF, ReqID, Handle, Attrs) ->
%% Read a symbolic link
readlink(XF, ReqID, Path) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
xf_request(XF, ?SSH_FXP_READLINK,
[?uint32(ReqID),
?binary(Path1)]).
@@ -235,8 +235,8 @@ readlink(XF, ReqID, Path) ->
%% Create a symbolic link
symlink(XF, ReqID, LinkPath, TargetPath) ->
- LinkPath1 = list_to_binary(LinkPath),
- TargetPath1 = list_to_binary(TargetPath),
+ LinkPath1 = unicode:characters_to_binary(LinkPath),
+ TargetPath1 = unicode:characters_to_binary(TargetPath),
xf_request(XF, ?SSH_FXP_SYMLINK,
[?uint32(ReqID),
?binary(LinkPath1),
@@ -244,7 +244,7 @@ symlink(XF, ReqID, LinkPath, TargetPath) ->
%% Convert a path into a 'canonical' form
realpath(XF, ReqID, Path) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
xf_request(XF, ?SSH_FXP_REALPATH,
[?uint32(ReqID),
?binary(Path1)]).
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index d5615fecfc..1645eb15f3 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -37,17 +37,21 @@
<list type="bulleted">
<item>ssl requires the crypto and public_key applications.</item>
<item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0,
- TLS-1.1 and TLS-1.2 (no support for elliptic curve cipher suites yet).</item>
+ TLS-1.1 and TLS-1.2.</item>
<item>For security reasons sslv2 is not supported.</item>
<item>Ephemeral Diffie-Hellman cipher suites are supported
but not Diffie Hellman Certificates cipher suites.</item>
+ <item>Elliptic Curve cipher suites are supported if crypto
+ supports it and named curves are used.
+ </item>
<item>Export cipher suites are not supported as the
U.S. lifted its export restrictions in early 2000.</item>
<item>IDEA cipher suites are not supported as they have
become deprecated by the latest TLS spec so there is not any
real motivation to implement them.</item>
- <item>CRL and policy certificate
- extensions are not supported yet. </item>
+ <item>CRL and policy certificate extensions are not supported
+ yet. However CRL verification is supported by public_key, only not integrated
+ in ssl yet. </item>
</list>
</section>
@@ -75,7 +79,7 @@
{fail_if_no_peer_cert, boolean()}
{depth, integer()} |
{cert, der_encoded()}| {certfile, path()} |
- {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}} |
+ {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}} |
{keyfile, path()} | {password, string()} |
{cacerts, [der_encoded()]} | {cacertfile, path()} |
|{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} |
@@ -125,6 +129,7 @@
<p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon
| psk | dhe_psk | rsa_psk | srp_anon | srp_dss | srp_rsa
+ | ecdh_anon | ecdh_ecdsa | ecdhe_ecdsa | ecdh_rsa | ecdhe_rsa
</c></p>
<p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc'
@@ -157,7 +162,7 @@
<tag>{certfile, path()}</tag>
<item>Path to a file containing the user's certificate.</item>
- <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}}</tag>
+ <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}}</tag>
<item> The DER encoded users private key. If this option
is supplied it will override the keyfile option.</item>
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index d3ba76d34e..3b8145089e 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -66,7 +66,7 @@ MODULES= \
INTERNAL_HRL_FILES = \
ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \
- ssl_record.hrl ssl_srp.hrl ssl_srp_primes.hrl
+ ssl_record.hrl ssl_srp.hrl
ERL_FILES= \
$(MODULES:%=%.erl) \
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 70f3b4f050..fb64a6652f 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -37,7 +37,6 @@
-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").
@@ -364,11 +363,11 @@ cipher_suites() ->
cipher_suites(erlang) ->
Version = ssl_record:highest_protocol_version([]),
- [suite_definition(S) || S <- ssl_cipher:suites(Version)];
+ [suite_definition(S) || S <- cipher_suites(Version, [])];
cipher_suites(openssl) ->
Version = ssl_record:highest_protocol_version([]),
- [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)];
+ [ssl_cipher:openssl_suite_name(S) || S <- cipher_suites(Version, [])];
cipher_suites(all) ->
Version = ssl_record:highest_protocol_version([]),
@@ -739,6 +738,7 @@ validate_option(key, {KeyType, Value}) when is_binary(Value),
KeyType == dsa; %% Backwards compatibility
KeyType == 'RSAPrivateKey';
KeyType == 'DSAPrivateKey';
+ KeyType == 'ECPrivateKey';
KeyType == 'PrivateKeyInfo' ->
{KeyType, Value};
@@ -947,21 +947,22 @@ emulated_options([], Inet,Emulated) ->
{Inet, Emulated}.
cipher_suites(Version, []) ->
- ssl_cipher:suites(Version);
+ ssl_cipher:filter_suites(ssl_cipher:suites(Version));
cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version)
+ Supported0 = ssl_cipher:suites(Version)
++ ssl_cipher:anonymous_suites()
++ ssl_cipher:psk_suites(Version)
++ ssl_cipher:srp_suites(),
- case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of
+ Supported1 = ssl_cipher:filter_suites(Supported0),
+ case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported1)] of
[] ->
- Supported;
+ Supported1;
Ciphers ->
Ciphers
end;
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 01a7cd93b5..9e1c3a09bf 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -37,7 +37,8 @@
is_valid_extkey_usage/2,
is_valid_key_usage/2,
select_extension/2,
- extensions_list/1
+ extensions_list/1,
+ public_key_type/1
]).
%%====================================================================
@@ -166,6 +167,18 @@ extensions_list(Extensions) ->
Extensions.
%%--------------------------------------------------------------------
+-spec public_key_type(term()) -> rsa | dsa | ec.
+%%
+%% Description:
+%%--------------------------------------------------------------------
+public_key_type(?'rsaEncryption') ->
+ rsa;
+public_key_type(?'id-dsa') ->
+ dsa;
+public_key_type(?'id-ecPublicKey') ->
+ ec.
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) ->
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index ff36b5ee26..cdff73336e 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -100,7 +100,7 @@ add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) ->
{ok, NewRef};
add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case lookup_cached_pem(Db, MD5) of
[{_Content, Ref}] ->
ref_count(Ref, RefDb, 1),
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 173c53709b..898b421dff 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -35,7 +35,7 @@
-export([security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
- openssl_suite/1, openssl_suite_name/1, filter/2,
+ openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1]).
-compile(inline).
@@ -73,25 +73,25 @@ cipher(?NULL, CipherState, <<>>, Fragment, _Version) ->
{GenStreamCipherList, CipherState};
cipher(?RC4, CipherState, Mac, Fragment, _Version) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
GenStreamCipherList = [Fragment, Mac],
- {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList),
+ {State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList),
{T, CipherState#cipher_state{state = State1}};
cipher(?DES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) ->
- crypto:des_cbc_encrypt(Key, IV, T)
+ crypto:block_encrypt(des_cbc, Key, IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?'3DES', CipherState, Mac, Fragment, Version) ->
block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_encrypt(K1, K2, K3, IV, T)
+ crypto:block_encrypt(des3_cbc, [K1, K2, K3], IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?AES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_encrypt(Key, IV, T);
+ crypto:block_encrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_encrypt(Key, IV, T)
+ crypto:block_encrypt(aes_cbc256, Key, IV, T)
end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version).
build_cipher_block(BlockSz, Mac, Fragment) ->
@@ -127,10 +127,10 @@ decipher(?NULL, _HashSz, CipherState, Fragment, _) ->
{Fragment, <<>>, CipherState};
decipher(?RC4, HashSz, CipherState, Fragment, _) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
- try crypto:rc4_encrypt_with_state(State0, Fragment) of
+ try crypto:stream_decrypt(State0, Fragment) of
{State, Text} ->
GSC = generic_stream_cipher_from_bin(Text, HashSz),
#generic_stream_cipher{content = Content, mac = Mac} = GSC,
@@ -147,17 +147,17 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) ->
decipher(?DES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) ->
- crypto:des_cbc_decrypt(Key, IV, T)
+ crypto:block_decrypt(des_cbc, Key, IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?'3DES', HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_decrypt(K1, K2, K3, IV, T)
+ crypto:block_decrypt(des3_cbc, [K1, K2, K3], IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?AES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_decrypt(Key, IV, T);
+ crypto:block_decrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_decrypt(Key, IV, T)
+ crypto:block_decrypt(aes_cbc256, Key, IV, T)
end, CipherState, HashSz, Fragment, Version).
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
@@ -212,10 +212,14 @@ anonymous_suites() ->
?TLS_DH_anon_WITH_AES_128_CBC_SHA,
?TLS_DH_anon_WITH_AES_256_CBC_SHA,
?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256].
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256,
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA,
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec psk_suites(tls_version()) -> [cipher_suite()].
+-spec psk_suites(tls_version() | integer()) -> [cipher_suite()].
%%
%% Description: Returns a list of the PSK cipher suites, only supported
%% if explicitly set by user.
@@ -274,6 +278,11 @@ srp_suites() ->
%% TLS v1.1 suites
suite_definition(?TLS_NULL_WITH_NULL_NULL) ->
{null, null, null, null};
+%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension
+%% to avoid handshake failure from old servers that do not ignore
+%% hello extension data as they should.
+suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) ->
+ {null, null, null, null};
%% suite_definition(?TLS_RSA_WITH_NULL_MD5) ->
%% {rsa, null, md5, default_prf};
%% suite_definition(?TLS_RSA_WITH_NULL_SHA) ->
@@ -423,8 +432,81 @@ suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
{srp_rsa, aes_256_cbc, sha, default_prf};
suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
- {srp_dss, aes_256_cbc, sha, default_prf}.
-
+ {srp_dss, aes_256_cbc, sha, default_prf};
+
+%% RFC 4492 EC TLS suites
+suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) ->
+ {ecdh_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdh_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) ->
+ {ecdhe_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdhe_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) ->
+ {ecdh_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ {ecdh_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) ->
+ {ecdhe_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ {ecdhe_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) ->
+ {ecdh_anon, null, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) ->
+ {ecdh_anon, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_anon, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) ->
+ {ecdh_anon, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) ->
+ {ecdh_anon, aes_256_cbc, sha, default_prf};
+
+%% RFC 5289 EC TLS suites
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_rsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_rsa, aes_256_cbc, sha384, sha384}.
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -573,7 +655,81 @@ suite({srp_anon, aes_256_cbc, sha}) ->
suite({srp_rsa, aes_256_cbc, sha}) ->
?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
suite({srp_dss, aes_256_cbc, sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA.
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+
+%%% RFC 4492 EC TLS suites
+suite({ecdh_ecdsa, null, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_NULL_SHA;
+suite({ecdh_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+suite({ecdh_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_ecdsa, null, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_NULL_SHA;
+suite({ecdhe_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+suite({ecdhe_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_rsa, null, sha}) ->
+ ?TLS_ECDH_RSA_WITH_NULL_SHA;
+suite({ecdh_rsa, rc4_128, sha}) ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+suite({ecdh_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_rsa, null, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_NULL_SHA;
+suite({ecdhe_rsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+suite({ecdhe_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_anon, null, sha}) ->
+ ?TLS_ECDH_anon_WITH_NULL_SHA;
+suite({ecdh_anon, rc4_128, sha}) ->
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA;
+suite({ecdh_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_anon, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
+suite({ecdh_anon, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
+
+%%% RFC 5289 EC TLS suites
+suite({ecdhe_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdhe_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -633,8 +789,62 @@ openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
openssl_suite("SRP-DSS-AES-128-CBC-SHA") ->
?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
openssl_suite("SRP-RSA-AES-128-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA.
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+%% RFC 4492 EC TLS suites
+openssl_suite("ECDH-ECDSA-RC4-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES128-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES256-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-ECDSA-RC4-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES128-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES256-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-RSA-RC4-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES128-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES256-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDH-RSA-RC4-SHA") ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-RSA-AES128-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-RSA-AES256-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+%% RFC 5289 EC TLS suites
+openssl_suite("ECDHE-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDHE-RSA-AES128-SHA256") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-RSA-AES256-SHA384") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-RSA-AES128-SHA256") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-RSA-AES256-SHA384") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
%%--------------------------------------------------------------------
-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
@@ -716,6 +926,61 @@ openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
"SRP-DSS-AES-256-CBC-SHA";
+%% RFC 4492 EC TLS suites
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDH-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDHE-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ "ECDH-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-RSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ "ECDHE-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-RSA-AES256-SHA";
+
+%% RFC 5289 EC TLS suites
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-RSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-RSA-AES256-SHA384";
+
%% No oppenssl name
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
@@ -730,14 +995,87 @@ filter(undefined, Ciphers) ->
filter(DerCert, Ciphers) ->
OtpCert = public_key:pkix_decode_cert(DerCert, otp),
SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm,
+ PubKeyInfo = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ PubKeyAlg = PubKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm,
+
+ Ciphers1 =
+ case ssl_certificate:public_key_type(PubKeyAlg#'PublicKeyAlgorithm'.algorithm) of
+ rsa ->
+ filter_keyuse(OtpCert, ((Ciphers -- dsa_signed_suites()) -- ec_keyed_suites()) -- ecdh_suites(),
+ rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites());
+ dsa ->
+ (Ciphers -- rsa_keyed_suites()) -- ec_keyed_suites();
+ ec ->
+ filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(),
+ [], ecdhe_ecdsa_suites())
+ end,
case public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm) of
{_, rsa} ->
- filter_rsa(OtpCert, Ciphers -- dsa_signed_suites());
+ Ciphers1 -- ecdsa_signed_suites();
{_, dsa} ->
- Ciphers -- rsa_signed_suites()
+ Ciphers1;
+ {_, ecdsa} ->
+ Ciphers1 -- rsa_signed_suites()
end.
%%--------------------------------------------------------------------
+-spec filter_suites([cipher_suite()]) -> [cipher_suite()].
+%%
+%% Description: filter suites for algorithms
+%%-------------------------------------------------------------------
+filter_suites(Suites = [{_,_,_}|_]) ->
+ Algos = crypto:supports(),
+ lists:filter(fun({KeyExchange, Cipher, Hash}) ->
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, proplists:get_value(hashs, Algos))
+ end, Suites);
+
+filter_suites(Suites = [{_,_,_,_}|_]) ->
+ Algos = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Algos),
+ lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) ->
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, Hashs) andalso
+ is_acceptable_prf(Prf, Hashs)
+ end, Suites);
+
+filter_suites(Suites) ->
+ Algos = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Algos),
+ lists:filter(fun(Suite) ->
+ {KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite),
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, Hashs) andalso
+ is_acceptable_prf(Prf, Hashs)
+ end, Suites).
+
+is_acceptable_keyexchange(KeyExchange, Algos)
+ when KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_rsa;
+ KeyExchange == ecdhe_rsa;
+ KeyExchange == ecdh_anon ->
+ proplists:get_bool(ecdh, Algos);
+is_acceptable_keyexchange(_, _) ->
+ true.
+
+is_acceptable_cipher(_, _) ->
+ true.
+
+is_acceptable_hash(null, _Algos) ->
+ true;
+is_acceptable_hash(Hash, Algos) ->
+ proplists:get_bool(Hash, Algos).
+
+is_acceptable_prf(default_prf, _) ->
+ true;
+is_acceptable_prf(Prf, Algos) ->
+ proplists:get_bool(Prf, Algos).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -950,7 +1288,13 @@ next_iv(Bin, IV) ->
rsa_signed_suites() ->
dhe_rsa_suites() ++ rsa_suites() ++
- psk_rsa_suites() ++ srp_rsa_suites().
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdh_rsa_suites().
+
+rsa_keyed_suites() ->
+ dhe_rsa_suites() ++ rsa_suites() ++
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdhe_rsa_suites().
dhe_rsa_suites() ->
[?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -982,7 +1326,25 @@ rsa_suites() ->
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_RSA_WITH_DES_CBC_SHA].
-
+
+ecdh_rsa_suites() ->
+ [?TLS_ECDH_RSA_WITH_NULL_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_rsa_suites() ->
+ [?TLS_ECDHE_RSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384].
+
dsa_signed_suites() ->
dhe_dss_suites() ++ srp_dss_suites().
@@ -999,24 +1361,52 @@ srp_dss_suites() ->
?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
-filter_rsa(OtpCert, RsaCiphers) ->
+ec_keyed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites()
+ ++ ecdh_rsa_suites().
+
+ecdsa_signed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites().
+
+ecdh_suites() ->
+ ecdh_rsa_suites() ++ ecdh_ecdsa_suites().
+
+ecdh_ecdsa_suites() ->
+ [?TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_ecdsa_suites() ->
+ [?TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384].
+
+filter_keyuse(OtpCert, Ciphers, Suites, SignSuites) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions,
Extensions = ssl_certificate:extensions_list(TBSExtensions),
case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of
undefined ->
- RsaCiphers;
+ Ciphers;
#'Extension'{extnValue = KeyUse} ->
- Result = filter_rsa_suites(keyEncipherment,
- KeyUse, RsaCiphers, rsa_suites()),
- filter_rsa_suites(digitalSignature,
- KeyUse, Result, dhe_rsa_suites())
+ Result = filter_keyuse_suites(keyEncipherment,
+ KeyUse, Ciphers, Suites),
+ filter_keyuse_suites(digitalSignature,
+ KeyUse, Result, SignSuites)
end.
-filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) ->
+filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) ->
case ssl_certificate:is_valid_key_usage(KeyUse, Use) of
true ->
CipherSuits;
false ->
- CipherSuits -- RsaSuites
+ CipherSuits -- Suites
end.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 90d3704efd..c7c71ee1a7 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
| aes_128_cbc | aes_256_cbc.
--type hash() :: null | sha | md5 | sha256 | sha384 | sha512.
+-type hash() :: null | sha | md5 | ssh224 | sha256 | sha384 | sha512.
-type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
--type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash()}.
+-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}.
-type cipher_suite() :: binary().
-type cipher_enum() :: integer().
-type openssl_cipher_suite() :: string().
@@ -219,6 +219,120 @@
%% TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D };
-define(TLS_DH_anon_WITH_AES_256_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#6D)>>).
+%% RFC 4492 EC TLS suites
+
+%% ECDH_ECDSA
+
+%% TLS_ECDH_ECDSA_WITH_NULL_SHA = { 0xC0, 0x01 }
+-define(TLS_ECDH_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#01)>>).
+
+%% TLS_ECDH_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x02 }
+-define(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#02)>>).
+
+%% TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x03 }
+-define(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#03)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x04 }
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#04)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x05 }
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#05)>>).
+
+%% ECDHE_ECDSA
+
+%% TLS_ECDHE_ECDSA_WITH_NULL_SHA = { 0xC0, 0x06 }
+-define(TLS_ECDHE_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#06)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x07 }
+-define(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#07)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x08 }
+-define(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#08)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x09 }
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#09)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0A }
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0A)>>).
+
+%% ECDH_RSA
+
+%% TLS_ECDH_RSA_WITH_NULL_SHA = { 0xC0, 0x0B }
+-define(TLS_ECDH_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#0B)>>).
+
+%% TLS_ECDH_RSA_WITH_RC4_128_SHA = { 0xC0, 0x0C }
+-define(TLS_ECDH_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#0C)>>).
+
+%% TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x0D }
+-define(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0D)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x0E }
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0E)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0F }
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0F)>>).
+
+%% ECDHE_RSA
+
+%% TLS_ECDHE_RSA_WITH_NULL_SHA = { 0xC0, 0x10 }
+-define(TLS_ECDHE_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#10)>>).
+
+%% TLS_ECDHE_RSA_WITH_RC4_128_SHA = { 0xC0, 0x11 }
+-define(TLS_ECDHE_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#11)>>).
+
+%% TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x12 }
+-define(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#12)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x13 }
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#13)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x14 }
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#14)>>).
+
+%% ECDH_anon
+
+%% TLS_ECDH_anon_WITH_NULL_SHA = { 0xC0, 0x15 }
+-define(TLS_ECDH_anon_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#15)>>).
+
+%% TLS_ECDH_anon_WITH_RC4_128_SHA = { 0xC0, 0x16 }
+-define(TLS_ECDH_anon_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#16)>>).
+
+%% TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x17 }
+-define(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#17)>>).
+
+%% TLS_ECDH_anon_WITH_AES_128_CBC_SHA = { 0xC0, 0x18 }
+-define(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#18)>>).
+
+%% TLS_ECDH_anon_WITH_AES_256_CBC_SHA = { 0xC0, 0x19 }
+-define(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#19)>>).
+
+
+%% RFC 5289 EC TLS suites
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x23};
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#23)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x24};
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#24)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x25};
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#25)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x26};
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#26)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x27};
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#27)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x28};
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#28)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x29};
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#29)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x2A};
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#2A)>>).
+
%%% Kerberos Cipher Suites
%% TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E };
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 1843377582..de9260fd8c 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -35,7 +35,6 @@
-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
@@ -98,7 +97,8 @@
terminated = false, %
allow_renegotiate = true,
expecting_next_protocol_negotiation = false :: boolean(),
- next_protocol = undefined :: undefined | binary()
+ next_protocol = undefined :: undefined | binary(),
+ client_ecc % {Curves, PointFmt}
}).
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
@@ -416,11 +416,14 @@ hello(Hello = #client_hello{client_version = ClientVersion},
ssl_options = SslOpts}) ->
case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise} ->
- do_server_hello(Type, ProtocolsToAdvertise, State#state{connection_states =
- ConnectionStates,
- negotiated_version = Version,
- session = Session});
+ {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves} ->
+ do_server_hello(Type, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves,
+ State#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ session = Session,
+ client_ecc = {EllipticCurves, EcPointFormats}});
#alert{} = Alert ->
handle_own_alert(Alert, ClientVersion, hello, State)
end;
@@ -533,7 +536,9 @@ certify(#certificate{} = Cert,
certify(#server_key_exchange{} = KeyExchangeMsg,
#state{role = client, negotiated_version = Version,
key_algorithm = Alg} = State0)
- when Alg == dhe_dss; Alg == dhe_rsa; Alg == dh_anon;
+ when Alg == dhe_dss; Alg == dhe_rsa;
+ Alg == ecdhe_rsa; Alg == ecdhe_ecdsa;
+ Alg == dh_anon; Alg == ecdh_anon;
Alg == psk; Alg == dhe_psk; Alg == rsa_psk;
Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon ->
case handle_server_key(KeyExchangeMsg, State0) of
@@ -669,9 +674,20 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
#state{negotiated_version = Version,
diffie_hellman_params = #'DHParameter'{prime = P,
- base = G},
+ base = G} = Params,
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
- case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ case dh_master_secret(Params, ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_ec_diffie_hellman_public{dh_public = ClientPublicEcDhPoint},
+ #state{negotiated_version = Version,
+ diffie_hellman_keys = ECDHKey} = State0) ->
+ case ec_dh_master_secret(ECDHKey, #'ECPoint'{point = ClientPublicEcDhPoint}, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
@@ -696,7 +712,7 @@ certify_client_key_exchange(#client_dhe_psk_identity{
diffie_hellman_params = #'DHParameter'{prime = P,
base = G},
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
- case dhe_psk_master_secret(ClientPSKIdentity, crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ case dhe_psk_master_secret(ClientPSKIdentity, P, G, ClientPublicDhKey, ServerDhPrivateKey, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
@@ -1278,6 +1294,7 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) ->
[PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
PKey =:= 'RSAPrivateKey' orelse
PKey =:= 'DSAPrivateKey' orelse
+ PKey =:= 'ECPrivateKey' orelse
PKey =:= 'PrivateKeyInfo'
],
private_key(public_key:pem_entry_decode(PemEntry, Password))
@@ -1291,6 +1308,8 @@ init_private_key(_,{rsa, PrivateKey}, _, _,_) ->
init_private_key('RSAPrivateKey', PrivateKey);
init_private_key(_,{dsa, PrivateKey},_,_,_) ->
init_private_key('DSAPrivateKey', PrivateKey);
+init_private_key(_,{ec, PrivateKey},_,_,_) ->
+ init_private_key('ECPrivateKey', PrivateKey);
init_private_key(_,{Asn1Type, PrivateKey},_,_,_) ->
private_key(init_private_key(Asn1Type, PrivateKey)).
@@ -1306,6 +1325,7 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'},
privateKey = Key}) ->
public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key));
+
private_key(Key) ->
Key.
@@ -1357,7 +1377,15 @@ handle_peer_cert(PeerCert, PublicKeyInfo,
State1 = State0#state{session =
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
- {Record, State} = next_record(State1),
+ State2 = case PublicKeyInfo of
+ {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams} ->
+ ECDHKey = public_key:generate_key(PublicKeyParams),
+ State3 = State1#state{diffie_hellman_keys = ECDHKey},
+ ec_dh_master_secret(ECDHKey, PublicKey, State3);
+
+ _ -> State1
+ end,
+ {Record, State} = next_record(State2),
next_state(certify, certify, Record, State).
certify_client(#state{client_certificate_requested = true, role = client,
@@ -1407,15 +1435,18 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
-do_server_hello(Type, NextProtocolsToSend, #state{negotiated_version = Version,
- session = #session{session_id = SessId},
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _}}
+do_server_hello(Type, NextProtocolsToSend,
+ EcPointFormats, EllipticCurves,
+ #state{negotiated_version = Version,
+ session = #session{session_id = SessId},
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}}
= State0) when is_atom(Type) ->
ServerHello =
ssl_handshake:server_hello(SessId, Version,
- ConnectionStates0, Renegotiation, NextProtocolsToSend),
+ ConnectionStates0, Renegotiation,
+ NextProtocolsToSend, EcPointFormats, EllipticCurves),
State = server_hello(ServerHello,
State0#state{expecting_next_protocol_negotiation =
NextProtocolsToSend =/= undefined}),
@@ -1547,7 +1578,7 @@ server_hello_done(#state{transport_cb = Transport,
tls_handshake_history = Handshake}.
certify_server(#state{key_algorithm = Algo} = State)
- when Algo == dh_anon; Algo == psk; Algo == dhe_psk ->
+ when Algo == dh_anon; Algo == ecdh_anon; Algo == psk; Algo == dhe_psk; Algo == srp_anon ->
State;
certify_server(#state{transport_cb = Transport,
@@ -1574,7 +1605,7 @@ key_exchange(#state{role = server, key_algorithm = rsa} = State) ->
State;
key_exchange(#state{role = server, key_algorithm = Algo,
hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1585,13 +1616,13 @@ key_exchange(#state{role = server, key_algorithm = Algo,
when Algo == dhe_dss;
Algo == dhe_rsa;
Algo == dh_anon ->
- Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ DHKeys = public_key:generate_key(Params),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dh, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1599,9 +1630,41 @@ key_exchange(#state{role = server, key_algorithm = Algo,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
tls_handshake_history = Handshake};
+key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State)
+ when Algo == ecdh_ecdsa; Algo == ecdh_rsa ->
+ State#state{diffie_hellman_keys = Key};
+key_exchange(#state{role = server, key_algorithm = Algo,
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State)
+ when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
+ Algo == ecdh_anon ->
+
+ ECDHKeys = public_key:generate_key(select_curve(State)),
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake1} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ diffie_hellman_keys = ECDHKeys,
+ tls_handshake_history = Handshake1};
+
key_exchange(#state{role = server, key_algorithm = psk,
ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
State;
@@ -1633,7 +1696,7 @@ key_exchange(#state{role = server, key_algorithm = psk,
key_exchange(#state{role = server, key_algorithm = dhe_psk,
ssl_options = #ssl_options{psk_identity = PskIdentityHint},
hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1641,13 +1704,13 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
socket = Socket,
transport_cb = Transport
} = State) ->
- Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ DHKeys = public_key:generate_key(Params),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1655,7 +1718,7 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
tls_handshake_history = Handshake};
key_exchange(#state{role = server, key_algorithm = rsa_psk,
@@ -1756,6 +1819,23 @@ key_exchange(#state{role = client,
tls_handshake_history = Handshake};
key_exchange(#state{role = client,
+ connection_states = ConnectionStates0,
+ key_algorithm = Algorithm,
+ negotiated_version = Version,
+ diffie_hellman_keys = Keys,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State)
+ when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
+ Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
+ Algorithm == ecdh_anon ->
+ Msg = ssl_handshake:key_exchange(client, Version, {ecdh, Keys}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
ssl_options = SslOpts,
connection_states = ConnectionStates0,
key_algorithm = psk,
@@ -1936,7 +2016,7 @@ handle_server_key(#server_key_exchange{exchange_keys = Keys},
Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version),
HashSign = connection_hashsign(Params#server_key_params.hashsign, State),
case HashSign of
- {_, anon} ->
+ {_, SignAlgo} when SignAlgo == anon; SignAlgo == ecdh_anon ->
server_master_secret(Params#server_key_params.params, State);
_ ->
verify_server_key(Params, HashSign, State)
@@ -1969,6 +2049,11 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh
State) ->
dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey},
+ State) ->
+ ECDHKeys = public_key:generate_key(ECCurve),
+ ec_dh_master_secret(ECDHKeys, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = ECDHKeys});
+
server_master_secret(#server_psk_params{
hint = IdentityHint},
State) ->
@@ -2000,17 +2085,23 @@ master_from_premaster_secret(PremasterSecret,
Alert
end.
+dh_master_secret(#'DHParameter'{} = Params, OtherPublicDhKey, MyPrivateKey, State) ->
+ PremasterSecret =
+ public_key:compute_key(OtherPublicDhKey, MyPrivateKey, Params),
+ master_from_premaster_secret(PremasterSecret, State).
+
dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
- Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+ Keys = {_, PrivateDhKey} = crypto:generate_key(dh, [Prime, Base]),
+ dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+
+dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State) ->
+ PremasterSecret =
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey, [Prime, Base]),
+ master_from_premaster_secret(PremasterSecret, State).
-dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
+ec_dh_master_secret(ECDHKeys, ECPoint, State) ->
PremasterSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+ public_key:compute_key(ECPoint, ECDHKeys),
master_from_premaster_secret(PremasterSecret, State).
handle_psk_identity(_PSKIdentity, LookupFun)
@@ -2033,20 +2124,18 @@ server_psk_master_secret(ClientPSKIdentity,
end.
dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+ crypto:generate_key(dh, [Prime, Base]),
+ dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
State#state{diffie_hellman_keys = Keys});
-dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
#state{ssl_options = SslOpts} = State) ->
case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
{ok, PSK} when is_binary(PSK) ->
DHSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey,
+ [Prime, Base]),
DHLen = erlang:byte_size(DHSecret),
Len = erlang:byte_size(PSK),
PremasterSecret = <<?UINT16(DHLen), DHSecret/binary, ?UINT16(Len), PSK/binary>>,
@@ -2075,7 +2164,7 @@ generate_srp_server_keys(_SrpParams, 10) ->
generate_srp_server_keys(SrpParams =
#srp_user{generator = Generator, prime = Prime,
verifier = Verifier}, N) ->
- case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of
+ case crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of
error ->
generate_srp_server_keys(SrpParams, N+1);
Keys ->
@@ -2086,7 +2175,7 @@ generate_srp_client_keys(_Generator, _Prime, 10) ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
generate_srp_client_keys(Generator, Prime, N) ->
- case crypto:srp_generate_key(Generator, Prime, '6a') of
+ case crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of
error ->
generate_srp_client_keys(Generator, Prime, N+1);
Keys ->
@@ -2098,7 +2187,7 @@ handle_srp_identity(Username, {Fun, UserState}) ->
{ok, {SRPParams, Salt, DerivedKey}}
when is_atom(SRPParams), is_binary(Salt), is_binary(DerivedKey) ->
{Generator, Prime} = ssl_srp_primes:get_srp_params(SRPParams),
- Verifier = crypto:mod_exp_prime(Generator, DerivedKey, Prime),
+ Verifier = crypto:mod_pow(Generator, DerivedKey, Prime),
#srp_user{generator = Generator, prime = Prime,
salt = Salt, verifier = Verifier};
#alert{} = Alert ->
@@ -2107,8 +2196,8 @@ handle_srp_identity(Username, {Fun, UserState}) ->
throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
end.
-server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = {ServerPub, ServerPriv}}) ->
- case crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, '6a') of
+server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = ServerKeys}) ->
+ case crypto:compute_key(srp, ClientPub, ServerKeys, {host, [Verifier, Prime, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
PremasterSecret ->
@@ -2121,14 +2210,13 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, undefined, State) ->
Keys = generate_srp_client_keys(Generator, Prime, 0),
client_srp_master_secret(Generator, Prime, Salt, ServerPub, Keys, State#state{srp_keys = Keys});
-client_srp_master_secret(Generator, Prime, Salt, ServerPub, {ClientPub, ClientPriv},
- #state{ssl_options = SslOpts} = State) ->
+client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys,
+ #state{ssl_options = SslOpts} = State) ->
case ssl_srp_primes:check_srp_params(Generator, Prime) of
ok ->
{Username, Password} = SslOpts#ssl_options.srp_identity,
- DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
-
- case crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, '6a') of
+ DerivedKey = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
+ case crypto:compute_key(srp, ServerPub, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
PremasterSecret ->
@@ -2798,11 +2886,6 @@ make_premaster_secret({MajVer, MinVer}, rsa) ->
make_premaster_secret(_, _) ->
undefined.
-mpint_binary(Binary) ->
- Size = erlang:byte_size(Binary),
- <<?UINT32(Size), Binary/binary>>.
-
-
ack_connection(#state{renegotiation = {true, Initiater}} = State)
when Initiater == internal;
Initiater == peer ->
@@ -2938,21 +3021,29 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange)
(KeyExchange == rsa orelse
KeyExchange == dhe_rsa orelse
KeyExchange == dh_rsa orelse
+ KeyExchange == ecdhe_rsa orelse
KeyExchange == srp_rsa) ->
{sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == rsa;
KeyExchange == dhe_rsa;
KeyExchange == dh_rsa;
+ KeyExchange == ecdhe_rsa;
KeyExchange == srp_rsa ->
{md5sha, rsa};
default_hashsign(_Version, KeyExchange)
+ when KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdh_rsa ->
+ {sha, ecdsa};
+default_hashsign(_Version, KeyExchange)
when KeyExchange == dhe_dss;
KeyExchange == dh_dss;
KeyExchange == srp_dss ->
{sha, dsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == dh_anon;
+ KeyExchange == ecdh_anon;
KeyExchange == psk;
KeyExchange == dhe_psk;
KeyExchange == rsa_psk;
@@ -2987,3 +3078,8 @@ handle_close_alert(Data, StateName, State0) ->
_ ->
ok
end.
+
+select_curve(#state{client_ecc = {[Curve|_], _}}) ->
+ {namedCurve, Curve};
+select_curve(_) ->
+ {namedCurve, ?secp256k1}.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 83c0092de2..24ea86311f 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -31,7 +31,7 @@
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([master_secret/4, client_hello/8, server_hello/5, hello/4,
+-export([master_secret/4, client_hello/8, server_hello/7, hello/4,
hello_request/0, certify/7, certificate/4,
client_certificate_verify/6, certificate_verify/6, verify_signature/5,
certificate_request/3, key_exchange/3, server_key_exchange_hash/2,
@@ -47,6 +47,8 @@
#client_key_exchange{} | #finished{} | #certificate_verify{} |
#hello_request{} | #next_protocol{}.
+-define(NAMED_CURVE_TYPE, 3).
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -67,6 +69,7 @@ client_hello(Host, Port, ConnectionStates,
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
SRP = srp_user(SslOpts),
+ {EcPointFormats, EllipticCurves} = default_ecc_extensions(Version),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -80,6 +83,8 @@ client_hello(Host, Port, ConnectionStates,
renegotiation_info(client, ConnectionStates, Renegotiation),
srp = SRP,
hash_signs = default_hash_signs(),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation =
encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation)
}.
@@ -96,11 +101,14 @@ encode_protocols_advertised_on_server(Protocols) ->
%%--------------------------------------------------------------------
-spec server_hello(session_id(), tls_version(), #connection_states{},
- boolean(), [binary()] | undefined) -> #server_hello{}.
+ boolean(), [binary()] | undefined,
+ #ec_point_formats{} | undefined,
+ #elliptic_curves{} | undefined) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
-server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdvertisedOnServer) ->
+server_hello(SessionId, Version, ConnectionStates, Renegotiation,
+ ProtocolsAdvertisedOnServer, EcPointFormats, EllipticCurves) ->
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
#server_hello{server_version = Version,
@@ -111,6 +119,8 @@ server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdver
session_id = SessionId,
renegotiation_info =
renegotiation_info(server, ConnectionStates, Renegotiation),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = encode_protocols_advertised_on_server(ProtocolsAdvertisedOnServer)
}.
@@ -129,7 +139,8 @@ hello_request() ->
atom(), #connection_states{}, binary()},
boolean()) ->
{tls_version(), session_id(), #connection_states{}, binary() | undefined}|
- {tls_version(), {resumed | new, #session{}}, #connection_states{}, list(binary()) | undefined} |
+ {tls_version(), {resumed | new, #session{}}, #connection_states{}, [binary()] | undefined,
+ [oid()] | undefined, [oid()] | undefined} |
#alert{}.
%%
%% Description: Handles a recieved hello message
@@ -163,44 +174,27 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
end;
-hello(#client_hello{client_version = ClientVersion, random = Random,
- cipher_suites = CipherSuites,
- renegotiation_info = Info,
- srp = SRP} = Hello,
- #ssl_options{versions = Versions,
- secure_renegotiate = SecureRenegotation} = SslOpts,
+hello(#client_hello{client_version = ClientVersion} = Hello,
+ #ssl_options{versions = Versions} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
-%% TODO: select hash and signature algorithm
+ %% TODO: select hash and signature algorithm
Version = select_version(ClientVersion, Versions),
case ssl_record:is_acceptable_version(Version, Versions) of
true ->
- {Type, #session{cipher_suite = CipherSuite,
- compression_method = Compression} = Session1}
+ %% TODO: need to take supported Curves into Account when selecting the CipherSuite....
+ %% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers
+ {Type, #session{cipher_suite = CipherSuite} = Session1}
= select_session(Hello, Port, Session0, Version,
SslOpts, Cache, CacheCb, Cert),
case CipherSuite of
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
- Session = handle_srp_info(SRP, Session1),
- case handle_renegotiation_info(server, Info, ConnectionStates0,
- Renegotiation, SecureRenegotation,
- CipherSuites) of
- {ok, ConnectionStates1} ->
- ConnectionStates =
- hello_pending_connection_states(server,
- Version,
- CipherSuite,
- Random,
- Compression,
- ConnectionStates1),
- case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
- #alert{} = Alert ->
- Alert;
- ProtocolsToAdvertise ->
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise}
- end;
- #alert{} = Alert ->
+ try handle_hello_extensions(Hello, Version, SslOpts, Session1, ConnectionStates0, Renegotiation) of
+ {Session, ConnectionStates, ProtocolsToAdvertise, ECPointFormats, EllipticCurves} ->
+ {Version, {Type, Session}, ConnectionStates,
+ ProtocolsToAdvertise, ECPointFormats, EllipticCurves}
+ catch throw:Alert ->
Alert
end
end;
@@ -350,9 +344,10 @@ verify_signature(_Version, Hash, _HashAlgo, Signature, {?rsaEncryption, PubKey,
_ -> false
end;
verify_signature(_Version, Hash, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) ->
+ public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams});
+verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, {?'id-ecPublicKey', PublicKey, PublicKeyParams}) ->
public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}).
-
%%--------------------------------------------------------------------
-spec certificate_request(#connection_states{}, db_handle(), certdb_ref()) ->
#certificate_request{}.
@@ -378,6 +373,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
binary(), binary(), private_key()} |
+ {ecdh, #'ECPrivateKey'{}} |
{psk, binary()} |
{dhe_psk, binary(), binary()} |
{srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
@@ -391,19 +387,25 @@ key_exchange(client, _Version, {premaster_secret, Secret, {_, PublicKey, _}}) ->
encrypted_premaster_secret(Secret, PublicKey),
#client_key_exchange{exchange_keys = EncPremasterSecret};
-key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+key_exchange(client, _Version, {dh, PublicKey}) ->
#client_key_exchange{
exchange_keys = #client_diffie_hellman_public{
dh_public = PublicKey}
};
+key_exchange(client, _Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey}}}) ->
+ #client_key_exchange{
+ exchange_keys = #client_ec_diffie_hellman_public{
+ dh_public = ECPublicKey}
+ };
+
key_exchange(client, _Version, {psk, Identity}) ->
#client_key_exchange{
exchange_keys = #client_psk_identity{
identity = Identity}
};
-key_exchange(client, _Version, {dhe_psk, Identity, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+key_exchange(client, _Version, {dhe_psk, Identity, PublicKey}) ->
#client_key_exchange{
exchange_keys = #client_dhe_psk_identity{
identity = Identity,
@@ -415,7 +417,7 @@ key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, P
encrypted_premaster_secret(Secret, PublicKey),
#client_key_exchange{
exchange_keys = #client_rsa_psk_identity{
- identity = PskIdentity,
+ identity = PskIdentity,
exchange_keys = EncPremasterSecret}};
key_exchange(client, _Version, {srp, PublicKey}) ->
@@ -424,31 +426,34 @@ key_exchange(client, _Version, {srp, PublicKey}) ->
srp_a = PublicKey}
};
-key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
- #'DHParameter'{prime = P, base = G},
- HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
- <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
- <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
- ServerDHParams = #server_dh_params{dh_p = PBin,
- dh_g = GBin, dh_y = PublicKey},
+key_exchange(server, Version, {dh, {PublicKey, _},
+ #'DHParameter'{prime = P, base = G},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerDHParams = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey},
enc_server_key_exchange(Version, ServerDHParams, HashSign,
ClientRandom, ServerRandom, PrivateKey);
+key_exchange(server, Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey},
+ parameters = ECCurve}, HashSign, ClientRandom, ServerRandom,
+ PrivateKey}) ->
+ ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPublicKey},
+ enc_server_key_exchange(Version, ServerECParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
key_exchange(server, Version, {psk, PskIdentityHint,
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
ServerPSKParams = #server_psk_params{hint = PskIdentityHint},
enc_server_key_exchange(Version, ServerPSKParams, HashSign,
ClientRandom, ServerRandom, PrivateKey);
-key_exchange(server, Version, {dhe_psk, PskIdentityHint, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
+key_exchange(server, Version, {dhe_psk, PskIdentityHint, {PublicKey, _},
#'DHParameter'{prime = P, base = G},
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
- <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
- <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
ServerEDHPSKParams = #server_dhe_psk_params{
hint = PskIdentityHint,
- dh_params = #server_dh_params{dh_p = PBin,
- dh_g = GBin, dh_y = PublicKey}
+ dh_params = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey}
},
enc_server_key_exchange(Version, ServerEDHPSKParams,
HashSign, ClientRandom, ServerRandom, PrivateKey);
@@ -591,6 +596,7 @@ get_tls_handshake(Version, Data, Buffer) ->
-spec decode_client_key(binary(), key_algo(), tls_version()) ->
#encrypted_premaster_secret{}
| #client_diffie_hellman_public{}
+ | #client_ec_diffie_hellman_public{}
| #client_psk_identity{}
| #client_dhe_psk_identity{}
| #client_rsa_psk_identity{}
@@ -661,8 +667,8 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) ->
%% Description: Calculate server key exchange hash
%%--------------------------------------------------------------------
server_key_exchange_hash(md5sha, Value) ->
- MD5 = crypto:md5(Value),
- SHA = crypto:sha(Value),
+ MD5 = crypto:hash(md5, Value),
+ SHA = crypto:hash(sha, Value),
<<MD5/binary, SHA/binary>>;
server_key_exchange_hash(Hash, Value) ->
@@ -833,10 +839,37 @@ select_next_protocol(Protocols, NextProtocolSelector) ->
Protocol
end.
-handle_srp_info(undefined, Session) ->
- Session;
-handle_srp_info(#srp{username = Username}, Session) ->
- Session#session{srp_username = Username}.
+default_ecc_extensions(Version) ->
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
+ true ->
+ EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]},
+ EllipticCurves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)},
+ {EcPointFormats, EllipticCurves};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) ->
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
+ true ->
+ EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0),
+ EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0),
+ {EcPointFormats1, EllipticCurves1};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_point_fmt_extension(undefined) ->
+ undefined;
+handle_ecc_point_fmt_extension(_) ->
+ #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}.
+
+handle_ecc_curves_extension(Version, undefined) ->
+ undefined;
+handle_ecc_curves_extension(Version, _) ->
+ #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}.
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
@@ -1022,6 +1055,8 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined),
SRP = proplists:get_value(srp, DecodedExtensions, undefined),
HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, DecodedExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined),
#client_hello{
@@ -1033,6 +1068,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
renegotiation_info = RenegotiationInfo,
srp = SRP,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation
};
@@ -1046,7 +1082,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
renegotiation_info = undefined,
- hash_signs = undefined};
+ hash_signs = undefined,
+ elliptic_curves = undefined};
dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
@@ -1058,6 +1095,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
undefined),
HashSigns = proplists:get_value(hash_signs, HelloExtensions,
undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, HelloExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, HelloExtensions, undefined),
#server_hello{
@@ -1068,6 +1107,7 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation};
dec_hs(_Version, ?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) ->
#certificate{asn1_certificates = certs_to_list(ASN1Certs)};
@@ -1111,6 +1151,11 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
#client_diffie_hellman_public{dh_public = DH_Y};
+dec_client_key(<<>>, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
+dec_client_key(<<?BYTE(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ #client_ec_diffie_hellman_public{dh_public = DH_Y};
dec_client_key(<<?UINT16(Len), Id:Len/binary>>,
?KEY_EXCHANGE_PSK, _) ->
#client_psk_identity{identity = Id};
@@ -1161,6 +1206,19 @@ dec_server_key(<<?UINT16(PLen), P:PLen/binary,
params_bin = BinMsg,
hashsign = HashSign,
signature = Signature};
+%% ECParameters with named_curve
+%% TODO: explicit curve
+dec_server_key(<<?BYTE(?NAMED_CURVE), ?UINT16(CurveID),
+ ?BYTE(PointLen), ECPoint:PointLen/binary,
+ _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, Version) ->
+ Params = #server_ecdh_params{curve = {namedCurve, ssl_tls1:enum_to_oid(CurveID)},
+ public = ECPoint},
+ {BinMsg, HashSign, Signature} = dec_ske_params(PointLen + 4, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
dec_server_key(<<?UINT16(Len), PskIdentityHint:Len/binary>> = KeyStruct,
KeyExchange, Version)
when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK ->
@@ -1237,6 +1295,22 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
dec_hello_extensions(Rest, [{hash_signs,
#hash_sign_algos{hash_sign_algos = HashSignAlgos}} | Acc]);
+dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ EllipticCurveListLen = Len - 2,
+ <<?UINT16(EllipticCurveListLen), EllipticCurveList/binary>> = ExtData,
+ EllipticCurves = [ssl_tls1:enum_to_oid(X) || <<X:16>> <= EllipticCurveList],
+ dec_hello_extensions(Rest, [{elliptic_curves,
+ #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]);
+
+dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ ECPointFormatListLen = Len - 1,
+ <<?BYTE(ECPointFormatListLen), ECPointFormatList/binary>> = ExtData,
+ ECPointFormats = binary_to_list(ECPointFormatList),
+ dec_hello_extensions(Rest, [{ec_point_formats,
+ #ec_point_formats{ec_point_format_list = ECPointFormats}} | Acc]);
+
%% Ignore data following the ClientHello (i.e.,
%% extensions) if not understood.
@@ -1287,13 +1361,17 @@ enc_hs(#client_hello{client_version = {Major, Minor},
renegotiation_info = RenegotiationInfo,
srp = SRP,
hash_signs = HashSigns,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SIDLength = byte_size(SessionID),
BinCompMethods = list_to_binary(CompMethods),
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation),
+ Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EcPointFormats)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EllipticCurves),
Extensions1 = if
Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns);
true -> Extensions0
@@ -1308,16 +1386,21 @@ enc_hs(#client_hello{client_version = {Major, Minor},
enc_hs(#server_hello{server_version = {Major, Minor},
random = Random,
session_id = Session_ID,
- cipher_suite = Cipher_suite,
+ cipher_suite = CipherSuite,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SID_length = byte_size(Session_ID),
- Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation),
+ CipherSuites = [ssl_cipher:suite_definition(CipherSuite)],
+ Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation)
+ ++ ec_hello_extensions(CipherSuites, EcPointFormats)
+ ++ ec_hello_extensions(CipherSuites, EllipticCurves),
ExtensionsBin = enc_hello_extensions(Extensions),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID/binary,
- Cipher_suite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
+ CipherSuite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) ->
ASN1Certs = certs_from_list(ASN1CertList),
ACLen = erlang:iolist_size(ASN1Certs),
@@ -1370,6 +1453,9 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) ->
enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
<<?UINT16(Len), DHPublic/binary>>;
+enc_cke(#client_ec_diffie_hellman_public{dh_public = DHPublic}, _) ->
+ Len = byte_size(DHPublic),
+ <<?BYTE(Len), DHPublic/binary>>;
enc_cke(#client_psk_identity{identity = undefined}, _) ->
Id = <<"psk_identity">>,
Len = byte_size(Id),
@@ -1398,6 +1484,11 @@ enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
GLen = byte_size(G),
YLen = byte_size(Y),
<<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_ecdh_params{curve = {namedCurve, ECCurve}, public = ECPubKey}) ->
+ %%TODO: support arbitrary keys
+ KLen = size(ECPubKey),
+ <<?BYTE(?NAMED_CURVE_TYPE), ?UINT16((ssl_tls1:oid_to_enum(ECCurve))),
+ ?BYTE(KLen), ECPubKey/binary>>;
enc_server_key(#server_psk_params{hint = PskIdentityHint}) ->
Len = byte_size(PskIdentityHint),
<<?UINT16(Len), PskIdentityHint/binary>>;
@@ -1431,11 +1522,46 @@ enc_sign(_HashSign, Sign, _Version) ->
SignLen = byte_size(Sign),
<<?UINT16(SignLen), Sign/binary>>.
+
+ec_hello_extensions(CipherSuites, #elliptic_curves{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(CipherSuites, #ec_point_formats{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(_, undefined) ->
+ [].
+
hello_extensions(RenegotiationInfo, NextProtocolNegotiation) ->
hello_extensions(RenegotiationInfo) ++ next_protocol_extension(NextProtocolNegotiation).
hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) ->
- hello_extensions(RenegotiationInfo) ++ hello_extensions(SRP) ++ next_protocol_extension(NextProtocolNegotiation).
+ hello_extensions(RenegotiationInfo)
+ ++ hello_extensions(SRP)
+ ++ next_protocol_extension(NextProtocolNegotiation).
+
+advertises_ec_ciphers([]) ->
+ false;
+advertises_ec_ciphers([{ecdh_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_anon, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([_| Rest]) ->
+ advertises_ec_ciphers(Rest).
%% Renegotiation info
hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) ->
@@ -1473,12 +1599,22 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest
InfoLen = byte_size(Info),
Len = InfoLen +1,
enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>);
-
+enc_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) ->
+ EllipticCurveList = << <<(ssl_tls1:oid_to_enum(X)):16>> || X <- EllipticCurves>>,
+ ListLen = byte_size(EllipticCurveList),
+ Len = ListLen + 2,
+ enc_hello_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
+ ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary, Acc/binary>>);
+enc_hello_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) ->
+ ECPointFormatList = list_to_binary(ECPointFormats),
+ ListLen = byte_size(ECPointFormatList),
+ Len = ListLen + 1,
+ enc_hello_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT),
+ ?UINT16(Len), ?BYTE(ListLen), ECPointFormatList/binary, Acc/binary>>);
enc_hello_extensions([#srp{username = UserName} | Rest], Acc) ->
SRPLen = byte_size(UserName),
Len = SRPLen + 2,
enc_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), UserName/binary, Acc/binary>>);
-
enc_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> ||
{Hash, Sign} <- HashSignAlgos >>,
@@ -1513,9 +1649,15 @@ from_2bytes(<<?UINT16(N), Rest/binary>>, Acc) ->
certificate_types({KeyExchange, _, _, _})
when KeyExchange == rsa;
KeyExchange == dhe_dss;
- KeyExchange == dhe_rsa ->
+ KeyExchange == dhe_rsa;
+ KeyExchange == ecdhe_rsa ->
<<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>;
+certificate_types({KeyExchange, _, _, _})
+ when KeyExchange == dh_ecdsa;
+ KeyExchange == dhe_ecdsa ->
+ <<?BYTE(?ECDSA_SIGN)>>;
+
certificate_types(_) ->
<<?BYTE(?RSA_SIGN)>>.
@@ -1532,9 +1674,6 @@ certificate_authorities(CertDbHandle, CertDbRef) ->
Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
- %%Subj = public_key:pkix_transform(OTPSubj, encode),
- %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
- %% DNEncodedBin = iolist_to_binary(DNEncoded),
DNEncodedLen = byte_size(DNEncodedBin),
<<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
end,
@@ -1555,7 +1694,9 @@ digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) ->
public_key:sign({digest, Hash}, HashAlgo, Key);
digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
- [{rsa_pad, rsa_pkcs1_padding}]).
+ [{rsa_pad, rsa_pkcs1_padding}]);
+digitally_signed(_Version, Hash, HashAlgo, Key) ->
+ public_key:sign({digest, Hash}, HashAlgo, Key).
calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) ->
ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom);
@@ -1588,6 +1729,10 @@ key_exchange_alg(rsa) ->
key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss;
Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon ->
?KEY_EXCHANGE_DIFFIE_HELLMAN;
+key_exchange_alg(Alg) when Alg == ecdhe_rsa; Alg == ecdh_rsa;
+ Alg == ecdhe_ecdsa; Alg == ecdh_ecdsa;
+ Alg == ecdh_anon ->
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN;
key_exchange_alg(psk) ->
?KEY_EXCHANGE_PSK;
key_exchange_alg(dhe_psk) ->
@@ -1612,15 +1757,71 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
-define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}).
-define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}).
+-define(TLSEXT_SIGALG_ECDSA(MD), {MD, ecdsa}).
--define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_RSA(MD)).
+-define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_ECDSA(MD), ?TLSEXT_SIGALG_RSA(MD)).
default_hash_signs() ->
+ HashSigns = [?TLSEXT_SIGALG(sha512),
+ ?TLSEXT_SIGALG(sha384),
+ ?TLSEXT_SIGALG(sha256),
+ ?TLSEXT_SIGALG(sha224),
+ ?TLSEXT_SIGALG(sha),
+ ?TLSEXT_SIGALG_DSA(sha),
+ ?TLSEXT_SIGALG_RSA(md5)],
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ HasECC = proplists:get_bool(ecdsa, CryptoSupport),
#hash_sign_algos{hash_sign_algos =
- [?TLSEXT_SIGALG(sha512),
- ?TLSEXT_SIGALG(sha384),
- ?TLSEXT_SIGALG(sha256),
- ?TLSEXT_SIGALG(sha224),
- ?TLSEXT_SIGALG(sha),
- ?TLSEXT_SIGALG_DSA(sha),
- ?TLSEXT_SIGALG_RSA(md5)]}.
+ lists:filter(fun({_, ecdsa}) -> HasECC;
+ (_) -> true end, HashSigns)}.
+
+handle_hello_extensions(#client_hello{random = Random,
+ cipher_suites = CipherSuites,
+ renegotiation_info = Info,
+ srp = SRP,
+ ec_point_formats = EcPointFormats0,
+ elliptic_curves = EllipticCurves0} = Hello, Version,
+ #ssl_options{secure_renegotiate = SecureRenegotation} = Opts,
+ Session0, ConnectionStates0, Renegotiation) ->
+ Session = handle_srp_extension(SRP, Session0),
+ ConnectionStates = handle_renegotiation_extension(Version, Info, Random, Session, ConnectionStates0,
+ Renegotiation, SecureRenegotation, CipherSuites),
+ ProtocolsToAdvertise = handle_next_protocol_extension(Hello, Renegotiation, Opts),
+ {EcPointFormats, EllipticCurves} = handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0),
+ %%TODO make extensions compund data structure
+ {Session, ConnectionStates, ProtocolsToAdvertise, EcPointFormats, EllipticCurves}.
+
+
+handle_renegotiation_extension(Version, Info, Random, #session{cipher_suite = CipherSuite,
+ compression_method = Compression},
+ ConnectionStates0, Renegotiation, SecureRenegotation, CipherSuites) ->
+ case handle_renegotiation_info(server, Info, ConnectionStates0,
+ Renegotiation, SecureRenegotation,
+ CipherSuites) of
+ {ok, ConnectionStates1} ->
+ hello_pending_connection_states(server,
+ Version,
+ CipherSuite,
+ Random,
+ Compression,
+ ConnectionStates1);
+ #alert{} = Alert ->
+ throw(Alert)
+ end.
+
+handle_next_protocol_extension(Hello, Renegotiation, SslOpts)->
+ case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
+ #alert{} = Alert ->
+ throw(Alert);
+ ProtocolsToAdvertise ->
+ ProtocolsToAdvertise
+ end.
+
+handle_srp_extension(undefined, Session) ->
+ Session;
+handle_srp_extension(#srp{username = Username}, Session) ->
+ Session#session{srp_username = Username}.
+
+int_to_bin(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ <<I:(L*8)>>.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 1fbb88f5f6..b2387a0ee7 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-include_lib("public_key/include/public_key.hrl").
--type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'.
--type public_key_params() :: #'Dss-Parms'{} | term().
--type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}.
+-type oid() :: tuple().
+-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
+-type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
-type tls_handshake_history() :: {[binary()], [binary()]}.
-define(NO_PROTOCOL, <<>>).
@@ -102,6 +102,8 @@
renegotiation_info,
srp, % srp username to send
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -113,6 +115,8 @@
compression_method, % compression_method
renegotiation_info,
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -130,6 +134,7 @@
-define(KEY_EXCHANGE_RSA, 0).
-define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1).
+-define(KEY_EXCHANGE_EC_DIFFIE_HELLMAN, 6).
-define(KEY_EXCHANGE_PSK, 2).
-define(KEY_EXCHANGE_DHE_PSK, 3).
-define(KEY_EXCHANGE_RSA_PSK, 4).
@@ -146,6 +151,11 @@
dh_y %% opaque DH_Ys<1..2^16-1>
}).
+-record(server_ecdh_params, {
+ curve,
+ public %% opaque encoded ECpoint
+ }).
+
-record(server_psk_params, {
hint
}).
@@ -195,6 +205,9 @@
-define(DSS_SIGN, 2).
-define(RSA_FIXED_DH, 3).
-define(DSS_FIXED_DH, 4).
+-define(ECDSA_SIGN, 64).
+-define(RSA_FIXED_ECDH, 65).
+-define(ECDSA_FIXED_ECDH, 66).
% opaque DistinguishedName<1..2^16-1>;
@@ -231,6 +244,10 @@
dh_public
}).
+-record(client_ec_diffie_hellman_public, {
+ dh_public
+ }).
+
-record(client_psk_identity, {
identity
}).
@@ -304,6 +321,33 @@
-record(next_protocol, {selected_protocol}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC Extensions RFC 4492 section 4 and 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(ELLIPTIC_CURVES_EXT, 10).
+-define(EC_POINT_FORMATS_EXT, 11).
+
+-record(elliptic_curves, {
+ elliptic_curve_list
+ }).
+
+-record(ec_point_formats, {
+ ec_point_format_list
+ }).
+
+-define(ECPOINT_UNCOMPRESSED, 0).
+-define(ECPOINT_ANSIX962_COMPRESSED_PRIME, 1).
+-define(ECPOINT_ANSIX962_COMPRESSED_CHAR2, 2).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC RFC 4492 Handshake Messages, Section 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(EXPLICIT_PRIME, 1).
+-define(EXPLICIT_CHAR2, 2).
+-define(NAMED_CURVE, 3).
+
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 96a1c8e1ce..14db4a6067 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,9 +37,9 @@
-type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
-type certdb_ref() :: reference().
-type db_handle() :: term().
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
-type der_cert() :: binary().
--type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
+-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | #'ECPrivateKey'{}.
-type issuer() :: tuple().
-type serialnumber() :: integer().
-type cert_key() :: {reference(), integer(), issuer()}.
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index aa9da65bb8..caea528a08 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -103,7 +103,7 @@ connection_init(Trustedcerts, Role) ->
%% Description: Cach a pem file and return its content.
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of
[{Content,_}] ->
{ok, Content};
@@ -468,7 +468,7 @@ new_id(Port, Tries, Cache, CacheCb) ->
clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->
case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
0 ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of
[{Content, Ref}] ->
ssl_certificate_db:insert(MD5, Content, PemCache);
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 26aca56739..2a3356d60f 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -712,12 +712,5 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
Length, Fragment).
sufficient_tlsv1_2_crypto_support() ->
- Data = "Sampl",
- Data2 = "e #1",
- Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39,
- 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>,
- try
- crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- true
- catch _:_ -> false
- end.
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
diff --git a/lib/ssl/src/ssl_srp_primes.hrl b/lib/ssl/src/ssl_srp_primes.hrl
deleted file mode 100644
index 4bd534efbf..0000000000
--- a/lib/ssl/src/ssl_srp_primes.hrl
+++ /dev/null
@@ -1 +0,0 @@
--type srp_parameters() :: srp_1024 | srp_1536 | srp_2048 | srp_3072 | srp_4096 | srp_6144 | srp_8192.
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index a11c5b8c0c..013c27ebb5 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -154,9 +154,9 @@ suites() ->
%%--------------------------------------------------------------------
hash(?MD5, Data) ->
- crypto:md5(Data);
+ crypto:hash(md5, Data);
hash(?SHA, Data) ->
- crypto:sha(Data).
+ crypto:hash(sha, Data).
%%pad_1(?NULL) ->
%% "";
@@ -198,6 +198,6 @@ gen(_Secret, _All, Wanted, Len, _C, _N, Acc) when Wanted =< Len ->
Block;
gen(Secret, All, Wanted, Len, C, N, Acc) ->
Prefix = lists:duplicate(N, C),
- SHA = crypto:sha([Prefix, All]),
- MD5 = crypto:md5([Secret, SHA]),
+ SHA = crypto:hash(sha, [Prefix, All]),
+ MD5 = crypto:hash(md5, [Secret, SHA]),
gen(Secret, All, Wanted, Len + 16, C+1, N+1, [MD5 | Acc]).
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index 41dc1bf0dc..8ab66d0627 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,7 +29,8 @@
-include("ssl_record.hrl").
-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7,
- setup_keys/8, suites/1, prf/5]).
+ setup_keys/8, suites/1, prf/5,
+ ecc_curves/1, oid_to_enum/1, enum_to_oid/1]).
%%====================================================================
%% Internal application API
@@ -57,8 +58,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
%% verify_data
%% PRF(master_secret, finished_label, MD5(handshake_messages) +
%% SHA-1(handshake_messages)) [0..11];
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12);
finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
@@ -76,8 +77,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary().
certificate_verify(md5sha, _Version, Handshake) ->
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
<<MD5/binary, SHA/binary>>;
certificate_verify(HashAlgo, _Version, Handshake) ->
@@ -183,24 +184,95 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
-spec suites(1|2|3) -> [cipher_suite()].
suites(Minor) when Minor == 1; Minor == 2->
+ case sufficent_ec_support() of
+ true ->
+ all_suites(Minor);
+ false ->
+ no_ec_suites(Minor)
+ end;
+
+suites(Minor) when Minor == 3 ->
+ case sufficent_ec_support() of
+ true ->
+ all_suites(3) ++ all_suites(2);
+ false ->
+ no_ec_suites(3) ++ no_ec_suites(2)
+ end.
+
+all_suites(Minor) when Minor == 1; Minor == 2->
[
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
?TLS_RSA_WITH_AES_256_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
?TLS_RSA_WITH_AES_128_CBC_SHA,
- %%?TLS_RSA_WITH_IDEA_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
+
?TLS_RSA_WITH_DES_CBC_SHA
- ];
+ ];
+all_suites(3) ->
+ [
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+ ?TLS_RSA_WITH_AES_256_CBC_SHA256,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA256
+ ].
-suites(Minor) when Minor == 3 ->
+no_ec_suites(Minor) when Minor == 1; Minor == 2->
+ [
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_WITH_RC4_128_SHA,
+ ?TLS_RSA_WITH_RC4_128_MD5,
+ ?TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ ?TLS_RSA_WITH_DES_CBC_SHA
+ ];
+no_ec_suites(3) ->
[
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
@@ -208,9 +280,7 @@ suites(Minor) when Minor == 3 ->
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
?TLS_RSA_WITH_AES_128_CBC_SHA256
- %% ?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- %% ?TLS_DH_anon_WITH_AES_256_CBC_SHA256
- ] ++ suites(2).
+ ].
%%--------------------------------------------------------------------
%%% Internal functions
@@ -218,16 +288,8 @@ suites(Minor) when Minor == 3 ->
%%%% HMAC and the Pseudorandom Functions RFC 2246 & 4346 - 5.%%%%
hmac_hash(?NULL, _, _) ->
<<>>;
-hmac_hash(?MD5, Key, Value) ->
- crypto:md5_mac(Key, Value);
-hmac_hash(?SHA, Key, Value) ->
- crypto:sha_mac(Key, Value);
-hmac_hash(?SHA256, Key, Value) ->
- crypto:sha256_mac(Key, Value);
-hmac_hash(?SHA384, Key, Value) ->
- crypto:sha384_mac(Key, Value);
-hmac_hash(?SHA512, Key, Value) ->
- crypto:sha512_mac(Key, Value).
+hmac_hash(Alg, Key, Value) ->
+ crypto:hmac(mac_algo(Alg), Key, Value).
mac_algo(?MD5) -> md5;
mac_algo(?SHA) -> sha;
@@ -303,3 +365,68 @@ finished_label(client) ->
<<"client finished">>;
finished_label(server) ->
<<"server finished">>.
+
+%% list ECC curves in prefered order
+ecc_curves(_Minor) ->
+ [?sect571r1,?sect571k1,?secp521r1,?sect409k1,?sect409r1,
+ ?secp384r1,?sect283k1,?sect283r1,?secp256k1,?secp256r1,
+ ?sect239k1,?sect233k1,?sect233r1,?secp224k1,?secp224r1,
+ ?sect193r1,?sect193r2,?secp192k1,?secp192r1,?sect163k1,
+ ?sect163r1,?sect163r2,?secp160k1,?secp160r1,?secp160r2].
+
+%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005)
+oid_to_enum(?sect163k1) -> 1;
+oid_to_enum(?sect163r1) -> 2;
+oid_to_enum(?sect163r2) -> 3;
+oid_to_enum(?sect193r1) -> 4;
+oid_to_enum(?sect193r2) -> 5;
+oid_to_enum(?sect233k1) -> 6;
+oid_to_enum(?sect233r1) -> 7;
+oid_to_enum(?sect239k1) -> 8;
+oid_to_enum(?sect283k1) -> 9;
+oid_to_enum(?sect283r1) -> 10;
+oid_to_enum(?sect409k1) -> 11;
+oid_to_enum(?sect409r1) -> 12;
+oid_to_enum(?sect571k1) -> 13;
+oid_to_enum(?sect571r1) -> 14;
+oid_to_enum(?secp160k1) -> 15;
+oid_to_enum(?secp160r1) -> 16;
+oid_to_enum(?secp160r2) -> 17;
+oid_to_enum(?secp192k1) -> 18;
+oid_to_enum(?secp192r1) -> 19;
+oid_to_enum(?secp224k1) -> 20;
+oid_to_enum(?secp224r1) -> 21;
+oid_to_enum(?secp256k1) -> 22;
+oid_to_enum(?secp256r1) -> 23;
+oid_to_enum(?secp384r1) -> 24;
+oid_to_enum(?secp521r1) -> 25.
+
+enum_to_oid(1) -> ?sect163k1;
+enum_to_oid(2) -> ?sect163r1;
+enum_to_oid(3) -> ?sect163r2;
+enum_to_oid(4) -> ?sect193r1;
+enum_to_oid(5) -> ?sect193r2;
+enum_to_oid(6) -> ?sect233k1;
+enum_to_oid(7) -> ?sect233r1;
+enum_to_oid(8) -> ?sect239k1;
+enum_to_oid(9) -> ?sect283k1;
+enum_to_oid(10) -> ?sect283r1;
+enum_to_oid(11) -> ?sect409k1;
+enum_to_oid(12) -> ?sect409r1;
+enum_to_oid(13) -> ?sect571k1;
+enum_to_oid(14) -> ?sect571r1;
+enum_to_oid(15) -> ?secp160k1;
+enum_to_oid(16) -> ?secp160r1;
+enum_to_oid(17) -> ?secp160r2;
+enum_to_oid(18) -> ?secp192k1;
+enum_to_oid(19) -> ?secp192r1;
+enum_to_oid(20) -> ?secp224k1;
+enum_to_oid(21) -> ?secp224r1;
+enum_to_oid(22) -> ?secp256k1;
+enum_to_oid(23) -> ?secp256r1;
+enum_to_oid(24) -> ?secp384r1;
+enum_to_oid(25) -> ?secp521r1.
+
+sufficent_ec_support() ->
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)).
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index 5b92e551a5..22dc951ac1 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -277,7 +296,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -298,13 +324,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -349,24 +386,37 @@ gen_dsa2(LSize, NSize) ->
X0 = prime(LSize),
P0 = prime((LSize div 2) +1),
- %% Choose L-bit prime modulus P such that p–1 is a multiple of q.
+ %% Choose L-bit prime modulus P such that p-1 is a multiple of q.
case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
error ->
gen_dsa2(LSize, NSize);
P ->
- G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
- %% such that This may be done by setting g = h^(p–1)/q mod p, commonly h=2 is used.
+ G = crypto:mod_pow(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
X = prime(20), %% Choose x by some random method, where 0 < x < q.
- Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
+ Y = crypto:mod_pow(G, X, P), %% Calculate y = g^x mod p.
- #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ #'DSAPrivateKey'{version=0, p = P, q = Q,
+ g = crypto:bytes_to_integer(G), y = crypto:bytes_to_integer(Y), x = X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+gen_ec2(CurveId) ->
+ {PubKey, PrivKey} = crypto:generate_key(ecdh, CurveId),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = binary_to_list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
- case is_prime(crypto:mpint(P), 50) of
+ case is_prime(P, 50) of
true -> P;
false -> dsa_search(T+1, P0, Q, Iter-1)
end;
@@ -377,38 +427,40 @@ dsa_search(_,_,_,_) ->
%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime(ByteSize) ->
Rand = odd_rand(ByteSize),
- crypto:erlint(prime_odd(Rand, 0)).
+ prime_odd(Rand, 0).
prime_odd(Rand, N) ->
case is_prime(Rand, 50) of
true ->
Rand;
false ->
- NotPrime = crypto:erlint(Rand),
- prime_odd(crypto:mpint(NotPrime+2), N+1)
+ prime_odd(Rand+2, N+1)
end.
%% see http://en.wikipedia.org/wiki/Fermat_primality_test
is_prime(_, 0) -> true;
is_prime(Candidate, Test) ->
- CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
- case crypto:mod_exp(CoPrime, Candidate, Candidate) of
- CoPrime -> is_prime(Candidate, Test-1);
- _ -> false
- end.
+ CoPrime = odd_rand(10000, Candidate),
+ Result = crypto:mod_pow(CoPrime, Candidate, Candidate) ,
+ is_prime(CoPrime, crypto:bytes_to_integer(Result), Candidate, Test).
+
+is_prime(CoPrime, CoPrime, Candidate, Test) ->
+ is_prime(Candidate, Test-1);
+is_prime(_,_,_,_) ->
+ false.
odd_rand(Size) ->
Min = 1 bsl (Size*8-1),
Max = (1 bsl (Size*8))-1,
- odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+ odd_rand(Min, Max).
odd_rand(Min,Max) ->
- Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
- BitSkip = (Sz+4)*8-1,
- case Rand of
- Odd = <<_:BitSkip, 1:1>> -> Odd;
- Even = <<_:BitSkip, 0:1>> ->
- crypto:mpint(crypto:erlint(Even)+1)
+ Rand = crypto:rand_uniform(Min,Max),
+ case Rand rem 2 of
+ 0 ->
+ Rand + 1;
+ _ ->
+ Rand
end.
extended_gcd(A, B) ->
@@ -427,3 +479,4 @@ pem_to_der(File) ->
der_to_pem(File, Entries) ->
PemBin = public_key:pem_encode(Entries),
file:write_file(File, PemBin).
+
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 5cedde5d27..c4a6cf1407 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -69,6 +69,7 @@ groups() ->
{session, [], session_tests()},
{renegotiate, [], renegotiate_tests()},
{ciphers, [], cipher_tests()},
+ {ciphers_ec, [], cipher_tests_ec()},
{error_handling_tests, [], error_handling_tests()}
].
@@ -76,6 +77,7 @@ all_versions_groups ()->
[{group, api},
{group, renegotiate},
{group, ciphers},
+ {group, ciphers_ec},
{group, error_handling_tests}].
@@ -156,10 +158,19 @@ cipher_tests() ->
anonymous_cipher_suites,
psk_cipher_suites,
psk_with_hint_cipher_suites,
+ psk_anon_cipher_suites,
+ psk_anon_with_hint_cipher_suites,
srp_cipher_suites,
+ srp_anon_cipher_suites,
srp_dsa_cipher_suites,
default_reject_anonymous].
+cipher_tests_ec() ->
+ [ciphers_ecdsa_signed_certs,
+ ciphers_ecdsa_signed_certs_openssl_names,
+ ciphers_ecdh_rsa_signed_certs,
+ ciphers_ecdh_rsa_signed_certs_openssl_names].
+
error_handling_tests()->
[controller_dies,
client_closes_socket,
@@ -185,10 +196,12 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
- Config = ssl_test_lib:cert_options(Config1),
+ Config2 = ssl_test_lib:make_ecdsa_cert(Config1),
+ Config3 = ssl_test_lib:make_ecdh_rsa_cert(Config2),
+ Config = ssl_test_lib:cert_options(Config3),
[{watchdog, Dog} | Config]
catch _:_ ->
{skip, "Crypto did not start"}
@@ -253,7 +266,7 @@ init_per_testcase(empty_protocol_versions, Config) ->
%% ssl_test_lib:make_mix_cert(Config0);
init_per_testcase(_TestCase, Config0) ->
- ct:print("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
+ ct:log("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ct:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
@@ -316,7 +329,7 @@ connection_info(Config) when is_list(Config) ->
[{ciphers,[{rsa,rc4_128,sha,no_export}]} |
ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
Version =
@@ -369,7 +382,7 @@ controlling_process(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
receive
@@ -419,7 +432,7 @@ controller_dies(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
+ ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
ct:sleep(?SLEEP), %% so that they are connected
process_flag(trap_exit, true),
@@ -457,12 +470,12 @@ controller_dies(Config) when is_list(Config) ->
Client3 ! die_nice
end,
- ct:print("Wating on exit ~p~n",[Client3]),
+ ct:log("Wating on exit ~p~n",[Client3]),
receive {'EXIT', Client3, normal} -> ok end,
receive %% Client3 is dead but that doesn't matter, socket should not be closed.
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 1000 ->
ok
@@ -593,7 +606,7 @@ peername(Config) when is_list(Config) ->
ServerMsg = {ok, {ClientIp, ClientPort}},
ClientMsg = {ok, {ServerIp, Port}},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -626,7 +639,7 @@ peercert(Config) when is_list(Config) ->
ServerMsg = {error, no_peercert},
ClientMsg = {ok, BinCert},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -664,7 +677,7 @@ peercert_with_client_cert(Config) when is_list(Config) ->
ServerMsg = {ok, ClientBinCert},
ClientMsg = {ok, ServerBinCert},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -696,7 +709,7 @@ sockname(Config) when is_list(Config) ->
ServerMsg = {ok, {ServerIp, Port}},
ClientMsg = {ok, {ClientIp, ClientPort}},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -769,7 +782,7 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
ssl:setopts(Socket, [{nodelay, true}]),
{ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
{ok, All} = ssl:getopts(Socket, []),
- ct:print("All opts ~p~n", [All]),
+ ct:log("All opts ~p~n", [All]),
ok.
@@ -792,7 +805,7 @@ invalid_inet_get_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -818,7 +831,7 @@ invalid_inet_get_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -850,7 +863,7 @@ invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -881,7 +894,7 @@ invalid_inet_set_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -913,7 +926,7 @@ invalid_inet_set_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -945,7 +958,7 @@ invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -986,7 +999,7 @@ misc_ssl_options(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, TestOpts ++ ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -999,7 +1012,7 @@ versions() ->
versions(Config) when is_list(Config) ->
[_|_] = Versions = ssl:versions(),
- ct:print("~p~n", [Versions]).
+ ct:log("~p~n", [Versions]).
%%--------------------------------------------------------------------
send_recv() ->
@@ -1021,7 +1034,7 @@ send_recv(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1047,7 +1060,7 @@ send_close(Config) when is_list(Config) ->
{ok, SslS} = rpc:call(ClientNode, ssl, connect,
[TcpS,[{active, false}|ClientOpts]]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), self(), Server]),
ok = ssl:send(SslS, "Hello world"),
{ok,<<"Hello world">>} = ssl:recv(SslS, 11),
@@ -1132,7 +1145,7 @@ upgrade(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1182,7 +1195,7 @@ upgrade_with_timeout(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1208,14 +1221,14 @@ tcp_connect(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
receive
{tcp_closed, Socket} ->
receive
{Server, {error, Error}} ->
- ct:print("Error ~p", [Error])
+ ct:log("Error ~p", [Error])
end
end.
%%--------------------------------------------------------------------
@@ -1236,7 +1249,7 @@ tcp_connect_big(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
gen_tcp:send(Socket, <<?BYTE(0),
@@ -1248,7 +1261,7 @@ tcp_connect_big(Config) when is_list(Config) ->
{Server, {error, timeout}} ->
ct:fail("hangs");
{Server, {error, Error}} ->
- ct:print("Error ~p", [Error])
+ ct:log("Error ~p", [Error])
end
end.
@@ -1278,7 +1291,7 @@ ipv6(Config) when is_list(Config) ->
{options,
[inet6, {active, false} | ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1536,8 +1549,8 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:rsa_suites(),
- ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ Ciphers = ssl_test_lib:rsa_suites(crypto),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
%%-------------------------------------------------------------------
ciphers_rsa_signed_certs_openssl_names() ->
@@ -1546,8 +1559,8 @@ ciphers_rsa_signed_certs_openssl_names() ->
ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:openssl_rsa_suites(),
- ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ Ciphers = ssl_test_lib:openssl_rsa_suites(crypto),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
%%-------------------------------------------------------------------
@@ -1559,7 +1572,7 @@ ciphers_dsa_signed_certs(Config) when is_list(Config) ->
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:dsa_suites(),
- ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
%%-------------------------------------------------------------------
ciphers_dsa_signed_certs_openssl_names() ->
@@ -1570,7 +1583,7 @@ ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_dsa_suites(),
- ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
%%-------------------------------------------------------------------
anonymous_cipher_suites()->
@@ -1594,6 +1607,20 @@ psk_with_hint_cipher_suites(Config) when is_list(Config) ->
Ciphers = ssl_test_lib:psk_suites(),
run_suites(Ciphers, Version, Config, psk_with_hint).
%%-------------------------------------------------------------------
+psk_anon_cipher_suites() ->
+ [{doc, "Test the anonymous PSK ciphersuites WITHOUT server supplied identity hint"}].
+psk_anon_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_anon_suites(),
+ run_suites(Ciphers, Version, Config, psk_anon).
+%%-------------------------------------------------------------------
+psk_anon_with_hint_cipher_suites()->
+ [{doc, "Test the anonymous PSK ciphersuites WITH server supplied identity hint"}].
+psk_anon_with_hint_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_anon_suites(),
+ run_suites(Ciphers, Version, Config, psk_anon_with_hint).
+%%-------------------------------------------------------------------
srp_cipher_suites()->
[{doc, "Test the SRP ciphersuites"}].
srp_cipher_suites(Config) when is_list(Config) ->
@@ -1601,6 +1628,13 @@ srp_cipher_suites(Config) when is_list(Config) ->
Ciphers = ssl_test_lib:srp_suites(),
run_suites(Ciphers, Version, Config, srp).
%%-------------------------------------------------------------------
+srp_anon_cipher_suites()->
+ [{doc, "Test the anonymous SRP ciphersuites"}].
+srp_anon_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:srp_anon_suites(),
+ run_suites(Ciphers, Version, Config, srp_anon).
+%%-------------------------------------------------------------------
srp_dsa_cipher_suites()->
[{doc, "Test the SRP DSA ciphersuites"}].
srp_dsa_cipher_suites(Config) when is_list(Config) ->
@@ -1632,6 +1666,48 @@ default_reject_anonymous(Config) when is_list(Config) ->
Client, {error, {tls_alert, "insufficient security"}}).
%%--------------------------------------------------------------------
+ciphers_ecdsa_signed_certs() ->
+ [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+
+ Ciphers = ssl_test_lib:ecdsa_suites(),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdsa).
+%%--------------------------------------------------------------------
+ciphers_ecdsa_signed_certs_openssl_names() ->
+ [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:openssl_ecdsa_suites(),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdsa).
+%%--------------------------------------------------------------------
+ciphers_ecdh_rsa_signed_certs() ->
+ [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+
+ Ciphers = ssl_test_lib:ecdh_rsa_suites(),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdh_rsa).
+%%--------------------------------------------------------------------
+ciphers_ecdh_rsa_signed_certs_openssl_names() ->
+ [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdh_rsa).
+%%--------------------------------------------------------------------
reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
reuse_session(Config) when is_list(Config) ->
@@ -1670,7 +1746,7 @@ reuse_session(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- ct:print("Expected: ~p, Unexpected: ~p~n",
+ ct:log("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
ct:fail(session_not_reused)
end,
@@ -1728,7 +1804,7 @@ reuse_session(Config) when is_list(Config) ->
ct:fail(
session_reused_when_session_reuse_disabled_by_server);
{Client4, _Other} ->
- ct:print("OTHER: ~p ~n", [_Other]),
+ ct:log("OTHER: ~p ~n", [_Other]),
ok
end,
@@ -1778,7 +1854,7 @@ reuse_session_expired(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- ct:print("Expected: ~p, Unexpected: ~p~n",
+ ct:log("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
ct:fail(session_not_reused)
end,
@@ -2481,7 +2557,7 @@ connect_twice(Config) when is_list(Config) ->
{options, [{keepalive, true},{active, false}
| ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -2827,9 +2903,9 @@ result_ok(_Socket) ->
ok.
renegotiate(Socket, Data) ->
- ct:print("Renegotiating ~n", []),
+ ct:log("Renegotiating ~n", []),
Result = ssl:renegotiate(Socket),
- ct:print("Result ~p~n", [Result]),
+ ct:log("Result ~p~n", [Result]),
ssl:send(Socket, Data),
case Result of
ok ->
@@ -2858,7 +2934,7 @@ renegotiate_immediately(Socket) ->
{error, renegotiation_rejected} = ssl:renegotiate(Socket),
ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
ok = ssl:renegotiate(Socket),
- ct:print("Renegotiated again"),
+ ct:log("Renegotiated again"),
ssl:send(Socket, "Hello world"),
ok.
@@ -2877,7 +2953,7 @@ new_config(PrivDir, ServerOpts0) ->
ServerOpts = proplists:delete(keyfile, ServerOpts2),
{ok, PEM} = file:read_file(NewCaCertFile),
- ct:print("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
+ ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
[{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
{keyfile, NewKeyFile} | ServerOpts].
@@ -3073,15 +3149,15 @@ get_close(Pid, Where) ->
{'EXIT', Pid, _Reason} ->
receive
{_, {ssl_closed, Socket}} ->
- ct:print("Socket closed ~p~n",[Socket]);
+ ct:log("Socket closed ~p~n",[Socket]);
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 5000 ->
ct:fail({timeout, {line, ?LINE, Where}})
end;
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 5000 ->
ct:fail({timeout, {line, ?LINE, Where}})
@@ -3095,7 +3171,7 @@ run_send_recv_rizzo(Ciphers, Config, Version, Mfa) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
@@ -3125,12 +3201,21 @@ rizzo_test(Cipher, Config, Version, Mfa) ->
[{Cipher, Error}]
end.
-client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa ->
+client_server_opts({KeyAlgo,_,_}, Config)
+ when KeyAlgo == rsa orelse
+ KeyAlgo == dhe_rsa orelse
+ KeyAlgo == ecdhe_rsa ->
{?config(client_opts, Config),
?config(server_opts, Config)};
client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss ->
{?config(client_dsa_opts, Config),
- ?config(server_dsa_opts, Config)}.
+ ?config(server_dsa_opts, Config)};
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_ecdsa orelse KeyAlgo == ecdhe_ecdsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdsa_opts, Config)};
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_rsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdh_rsa_opts, Config)}.
run_suites(Ciphers, Version, Config, Type) ->
{ClientOpts, ServerOpts} =
@@ -3151,12 +3236,27 @@ run_suites(Ciphers, Version, Config, Type) ->
psk_with_hint ->
{?config(client_psk, Config),
?config(server_psk_hint, Config)};
+ psk_anon ->
+ {?config(client_psk, Config),
+ ?config(server_psk_anon, Config)};
+ psk_anon_with_hint ->
+ {?config(client_psk, Config),
+ ?config(server_psk_anon_hint, Config)};
srp ->
{?config(client_srp, Config),
?config(server_srp, Config)};
+ srp_anon ->
+ {?config(client_srp, Config),
+ ?config(server_srp_anon, Config)};
srp_dsa ->
{?config(client_srp_dsa, Config),
- ?config(server_srp_dsa, Config)}
+ ?config(server_srp_dsa, Config)};
+ ecdsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdsa_opts, Config)};
+ ecdh_rsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdh_rsa_opts, Config)}
end,
Result = lists:map(fun(Cipher) ->
@@ -3166,7 +3266,7 @@ run_suites(Ciphers, Version, Config, Type) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
@@ -3177,7 +3277,7 @@ erlang_cipher_suite(Suite) ->
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
%% process_flag(trap_exit, true),
- ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 26938bda50..2703d2d79c 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -86,7 +86,7 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
@@ -297,7 +297,7 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
%% this is not a bug it is a circumstance of how tcp works!
receive
{Server, ServerError} ->
- ct:print("Server Error ~p~n", [ServerError])
+ ct:log("Server Error ~p~n", [ServerError])
end,
ssl_test_lib:check_result(Client, {error, {tls_alert, "handshake failure"}}).
@@ -346,7 +346,7 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
%% this is not a bug it is a circumstance of how tcp works!
receive
{Client, ClientError} ->
- ct:print("Client Error ~p~n", [ClientError])
+ ct:log("Client Error ~p~n", [ClientError])
end,
ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}).
@@ -413,7 +413,7 @@ cert_expired(Config) when is_list(Config) ->
two_digits_str(Sec)])),
NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}},
- ct:print("Validity: ~p ~n NewValidity: ~p ~n",
+ ct:log("Validity: ~p ~n NewValidity: ~p ~n",
[OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity},
@@ -644,7 +644,7 @@ no_authority_key_identifier(Config) when is_list(Config) ->
NewExtensions = delete_authority_key_extension(Extensions, []),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions},
- ct:print("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
+ ct:log("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
@@ -955,10 +955,10 @@ client_msg(Client, ClientMsg) ->
{Client, ClientMsg} ->
ok;
{Client, {error,closed}} ->
- ct:print("client got close"),
+ ct:log("client got close"),
ok;
{Client, {error, Reason}} ->
- ct:print("client got econnaborted: ~p", [Reason]),
+ ct:log("client got econnaborted: ~p", [Reason]),
ok;
Unexpected ->
ct:fail(Unexpected)
@@ -968,10 +968,10 @@ server_msg(Server, ServerMsg) ->
{Server, ServerMsg} ->
ok;
{Server, {error,closed}} ->
- ct:print("server got close"),
+ ct:log("server got close"),
ok;
{Server, {error, Reason}} ->
- ct:print("server got econnaborted: ~p", [Reason]),
+ ct:log("server got econnaborted: ~p", [Reason]),
ok;
Unexpected ->
ct:fail(Unexpected)
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 8c1b22cf5e..7b271c4d5d 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -74,7 +74,7 @@ init_per_suite(Config) ->
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -311,13 +311,13 @@ run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) ->
assert_npn(Socket, Protocol) ->
- ct:print("Negotiated Protocol ~p, Expecting: ~p ~n",
+ ct:log("Negotiated Protocol ~p, Expecting: ~p ~n",
[ssl:negotiated_next_protocol(Socket), Protocol]),
Protocol = ssl:negotiated_next_protocol(Socket).
assert_npn_and_renegotiate_and_send_data(Socket, Protocol, Data) ->
assert_npn(Socket, Protocol),
- ct:print("Renegotiating ~n", []),
+ ct:log("Renegotiating ~n", []),
ok = ssl:renegotiate(Socket),
ssl:send(Socket, Data),
assert_npn(Socket, Protocol),
@@ -332,7 +332,7 @@ ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ssl_receive(Socket, Data).
ssl_send(Socket, Data) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
ssl:send(Socket, Data).
@@ -340,11 +340,11 @@ ssl_receive(Socket, Data) ->
ssl_receive(Socket, Data, []).
ssl_receive(Socket, Data, Buffer) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, MoreData} ->
- ct:print("Received ~p~n",[MoreData]),
+ ct:log("Received ~p~n",[MoreData]),
NewBuffer = Buffer ++ MoreData,
case NewBuffer of
Data ->
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 72768bcb55..43fa72ea28 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -25,6 +25,8 @@
-compile(export_all).
-include("ssl_handshake.hrl").
-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_internal.hrl").
-include_lib("common_test/include/ct.hrl").
%%--------------------------------------------------------------------
@@ -75,17 +77,19 @@ encode_and_decode_npn_server_hello_test(_Config) ->
{[{DecodedHandshakeMessage, _Raw}], _} =
ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation,
- ct:print("~p ~n", [NextProtocolNegotiation]),
+ ct:log("~p ~n", [NextProtocolNegotiation]),
NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}.
%%--------------------------------------------------------------------
create_server_hello_with_no_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, undefined),
+ Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false,
+ undefined, undefined, undefined),
undefined = Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
create_server_hello_with_advertised_protocols_test(_Config) ->
Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
- false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]),
+ false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>],
+ undefined, undefined),
#next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} =
Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
@@ -96,7 +100,7 @@ create_client_handshake(Npn) ->
client_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
- cipher_suites = "",
+ cipher_suites = [?TLS_DHE_DSS_WITH_DES_CBC_SHA],
compression_methods = "",
next_protocol_negotiation = Npn,
renegotiation_info = #renegotiation_info{}
@@ -107,7 +111,7 @@ create_server_handshake(Npn) ->
server_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
- cipher_suite = <<1,2>>,
+ cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA,
compression_method = 1,
next_protocol_negotiation = Npn,
renegotiation_info = #renegotiation_info{}
@@ -119,7 +123,7 @@ create_connection_states() ->
security_parameters = #security_parameters{
server_random = <<1:256>>,
compression_algorithm = 1,
- cipher_suite = <<1, 2>>
+ cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA
}
},
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 4116bb39d1..5a374e234d 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -143,7 +143,7 @@ init_per_suite(Config) ->
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -2069,7 +2069,7 @@ client_packet_decode(Socket, [Head | Tail] = Packet) ->
client_packet_decode(Socket, [Head], Tail, Packet).
client_packet_decode(Socket, P1, P2, Packet) ->
- ct:print("Packet: ~p ~n", [Packet]),
+ ct:log("Packet: ~p ~n", [Packet]),
ok = ssl:send(Socket, P1),
ok = ssl:send(Socket, P2),
receive
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index 77ad546420..5f5166391f 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -556,33 +556,33 @@ send(Socket, Data, Size, Repeate,F) ->
sender(Socket, Data, Size) ->
ok = send(Socket, Data, Size, 100, fun() -> do_recv(Socket, Data, Size, <<>>, false) end),
- ct:print("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
sender_once(Socket, Data, Size) ->
send(Socket, Data, Size, 100,
fun() -> do_active_once(Socket, Data, Size, <<>>, false) end),
- ct:print("Sender active once: ~p~n",
+ ct:log("Sender active once: ~p~n",
[ssl:getopts(Socket, [active])]),
ok.
sender_active(Socket, Data, Size) ->
F = fun() -> do_active(Socket, Data, Size, <<>>, false) end,
send(Socket, Data, Size, 100, F),
- ct:print("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
echoer(Socket, Data, Size) ->
- ct:print("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_recv(Socket, Data, Size, <<>>, true) end, 100).
echoer_once(Socket, Data, Size) ->
- ct:print("Echoer active once: ~p ~n",
+ ct:log("Echoer active once: ~p ~n",
[ssl:getopts(Socket, [active])]),
echo(fun() -> do_active_once(Socket, Data, Size, <<>>, true) end, 100).
echoer_active(Socket, Data, Size) ->
- ct:print("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_active(Socket, Data, Size, <<>>, true) end, 100).
echo(_Fun, 0) -> ok;
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index fd9a0a594c..6cc6c4bdb2 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -63,7 +63,7 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index d655d7659e..34c52b10b3 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -59,7 +59,7 @@ run_server(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
{ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
@@ -77,13 +77,13 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("Server: apply(~p,~p,~p)~n",
+ ct:log("Server: apply(~p,~p,~p)~n",
[Module, Function, [AcceptSocket | Args]]),
case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:print("Server Msg: ~p ~n", [Msg]),
+ ct:log("Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
@@ -92,10 +92,10 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
{listen, MFA} ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
- ct:print("Server closing ~p ~n", [self()]),
+ ct:log("Server closing ~p ~n", [self()]),
Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
- ct:print("Result ~p : ~p ~n", [Result, Result1]);
+ ct:log("Result ~p : ~p ~n", [Result, Result1]);
{ssl_closed, _} ->
ok
end.
@@ -115,7 +115,7 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
end;
connect(ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
[ListenSocket]),
AcceptSocket.
@@ -123,10 +123,10 @@ connect(ListenSocket, Opts) ->
connect(_, _, 0, AcceptSocket, _) ->
AcceptSocket;
connect(ListenSocket, Node, N, _, Timeout) ->
- ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
[ListenSocket]),
- ct:print("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
+ ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
ok ->
@@ -161,27 +161,27 @@ run_client(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
{ok, Socket} ->
Pid ! { connected, Socket },
- ct:print("Client: connected~n", []),
+ ct:log("Client: connected~n", []),
%% In special cases we want to know the client port, it will
%% be indicated by sending {port, 0} in options list!
send_selected_port(Pid, proplists:get_value(port, Options), Socket),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("Client: apply(~p,~p,~p)~n",
+ ct:log("Client: apply(~p,~p,~p)~n",
[Module, Function, [Socket | Args]]),
case rpc:call(Node, Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:print("Client Msg: ~p ~n", [Msg]),
+ ct:log("Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
close ->
- ct:print("Client closing~n", []),
+ ct:log("Client closing~n", []),
rpc:call(Node, Transport, close, [Socket]);
{ssl_closed, Socket} ->
ok;
@@ -189,18 +189,18 @@ run_client(Opts) ->
ok
end;
{error, Reason} ->
- ct:print("Client: connection failed: ~p ~n", [Reason]),
+ ct:log("Client: connection failed: ~p ~n", [Reason]),
Pid ! {self(), {error, Reason}}
end.
close(Pid) ->
- ct:print("Close ~p ~n", [Pid]),
+ ct:log("Close ~p ~n", [Pid]),
Monitor = erlang:monitor(process, Pid),
Pid ! close,
receive
{'DOWN', Monitor, process, Pid, Reason} ->
erlang:demonitor(Monitor),
- ct:print("Pid: ~p down due to:~p ~n", [Pid, Reason])
+ ct:log("Pid: ~p down due to:~p ~n", [Pid, Reason])
end.
check_result(Server, ServerMsg, Client, ClientMsg) ->
@@ -285,7 +285,7 @@ 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">>])]),
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]),
{ok, {srp_1024, Salt, UserPassHash}}.
cert_options(Config) ->
@@ -339,12 +339,22 @@ cert_options(Config) ->
{psk_identity, "HINT"},
{user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
{ciphers, psk_suites()}]},
+ {server_psk_anon, [{ssl_imp, new},{reuseaddr, true},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_anon_suites()}]},
+ {server_psk_anon_hint, [{ssl_imp, new},{reuseaddr, true},
+ {psk_identity, "HINT"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_anon_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_srp_anon, [{ssl_imp, new},{reuseaddr, true},
+ {user_lookup_fun, {fun user_lookup/3, undefined}},
+ {ciphers, srp_anon_suites()}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -394,6 +404,51 @@ make_dsa_cert(Config) ->
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config].
+make_ecdsa_cert(Config) ->
+ CryptoSupport = crypto:supports(),
+ case proplists:get_bool(ecdsa, proplists:get_value(public_keys, CryptoSupport)) of
+ true ->
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, ec, ec, ""),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, ec, ec, ""),
+ [{server_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
+ {client_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ | Config];
+ _ ->
+ Config
+ end.
+
+%% RFC 4492, Sect. 2.3. ECDH_RSA
+%%
+%% This key exchange algorithm is the same as ECDH_ECDSA except that the
+%% server's certificate MUST be signed with RSA rather than ECDSA.
+make_ecdh_rsa_cert(Config) ->
+ CryptoSupport = crypto:supports(),
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)) of
+ true ->
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, rsa, ec, "rsa_"),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, rsa, ec, "rsa_"),
+ [{server_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_ecdh_rsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
+ {client_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ | Config];
+ _ ->
+ Config
+ end.
make_mix_cert(Config) ->
{ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa,
@@ -445,33 +500,33 @@ run_upgrade_server(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- ct:print("ssl:ssl_accept(~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
- ct:print("Upgrade Server Msg: ~p ~n", [Msg]),
+ ct:log("Upgrade Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:print("Upgrade Server closing~n", []),
+ ct:log("Upgrade Server closing~n", []),
rpc:call(Node, ssl, close, [SslAcceptSocket])
end
catch error:{badmatch, Error} ->
@@ -489,24 +544,24 @@ run_upgrade_client(Opts) ->
TcpOptions = proplists:get_value(tcp_options, Opts),
SslOptions = proplists:get_value(ssl_options, Opts),
- ct:print("gen_tcp:connect(~p, ~p, ~p)~n",
+ ct:log("gen_tcp:connect(~p, ~p, ~p)~n",
[Host, Port, TcpOptions]),
{ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
send_selected_port(Pid, Port, Socket),
- ct:print("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
+ ct:log("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
{ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("apply(~p, ~p, ~p)~n",
+ ct:log("apply(~p, ~p, ~p)~n",
[Module, Function, [SslSocket | Args]]),
Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
- ct:print("Upgrade Client Msg: ~p ~n", [Msg]),
+ ct:log("Upgrade Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:print("Upgrade Client closing~n", []),
+ ct:log("Upgrade Client closing~n", []),
rpc:call(Node, ssl, close, [SslSocket])
end.
@@ -525,20 +580,20 @@ run_upgrade_server_error(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
Error = case TimeOut of
infinity ->
- ct:print("ssl:ssl_accept(~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
@@ -558,26 +613,26 @@ run_server_error(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
case rpc:call(Node, Transport, listen, [Port, Options]) of
{ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
- ct:print("ssl:ssl_accept(~p)~n", [AcceptSocket]),
+ ct:log("ssl:ssl_accept(~p)~n", [AcceptSocket]),
Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
Pid ! {self(), Error}
end;
{ok, ListenSocket} ->
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("~p:accept(~p)~n", [Transport, ListenSocket]),
+ ct:log("~p:accept(~p)~n", [Transport, ListenSocket]),
case rpc:call(Node, Transport, accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error}
@@ -599,7 +654,7 @@ run_client_error(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
Pid ! {self(), Error}.
@@ -656,11 +711,16 @@ send_selected_port(Pid, 0, Socket) ->
send_selected_port(_,_,_) ->
ok.
-rsa_suites() ->
- lists:filter(fun({dhe_dss, _, _}) ->
- false;
+rsa_suites(CounterPart) ->
+ ECC = is_sane_ecc(CounterPart),
+ lists:filter(fun({rsa, _, _}) ->
+ true;
+ ({dhe_rsa, _, _}) ->
+ true;
+ ({ecdhe_rsa, _, _}) when ECC == true ->
+ true;
(_) ->
- true
+ false
end,
ssl:cipher_suites()).
@@ -680,17 +740,38 @@ dsa_suites() ->
end,
ssl:cipher_suites()).
+ecdsa_suites() ->
+ lists:filter(fun({ecdhe_ecdsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
-openssl_rsa_suites() ->
+ecdh_rsa_suites() ->
+ lists:filter(fun({ecdh_rsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
+
+openssl_rsa_suites(CounterPart) ->
Ciphers = ssl:cipher_suites(openssl),
+ Names = case is_sane_ecc(CounterPart) of
+ true ->
+ "DSS | ECDSA";
+ false ->
+ "DSS | ECDHE | ECDH"
+ end,
lists:filter(fun(Str) ->
- case re:run(Str,"DSS",[]) of
+ case re:run(Str, Names,[]) of
nomatch ->
- true;
+ false;
_ ->
- false
+ true
end
- end, Ciphers).
+ end, Ciphers).
openssl_dsa_suites() ->
Ciphers = ssl:cipher_suites(openssl),
@@ -703,14 +784,58 @@ openssl_dsa_suites() ->
end
end, Ciphers).
+openssl_ecdsa_suites() ->
+ Ciphers = ssl:cipher_suites(openssl),
+ lists:filter(fun(Str) ->
+ case re:run(Str,"ECDHE-ECDSA",[]) of
+ nomatch ->
+ false;
+ _ ->
+ true
+ end
+ end, Ciphers).
+
+openssl_ecdh_rsa_suites() ->
+ Ciphers = ssl:cipher_suites(openssl),
+ lists:filter(fun(Str) ->
+ case re:run(Str,"ECDH-RSA",[]) of
+ nomatch ->
+ false;
+ _ ->
+ true
+ end
+ end, Ciphers).
+
anonymous_suites() ->
- [{dh_anon, rc4_128, md5},
- {dh_anon, des_cbc, sha},
- {dh_anon, '3des_ede_cbc', sha},
- {dh_anon, aes_128_cbc, sha},
- {dh_anon, aes_256_cbc, sha}].
+ Suites =
+ [{dh_anon, rc4_128, md5},
+ {dh_anon, des_cbc, sha},
+ {dh_anon, '3des_ede_cbc', sha},
+ {dh_anon, aes_128_cbc, sha},
+ {dh_anon, aes_256_cbc, sha},
+ {ecdh_anon,rc4_128,sha},
+ {ecdh_anon,'3des_ede_cbc',sha},
+ {ecdh_anon,aes_128_cbc,sha},
+ {ecdh_anon,aes_256_cbc,sha}],
+ ssl_cipher:filter_suites(Suites).
psk_suites() ->
+ Suites =
+ [{psk, rc4_128, sha},
+ {psk, '3des_ede_cbc', sha},
+ {psk, aes_128_cbc, sha},
+ {psk, aes_256_cbc, sha},
+ {dhe_psk, rc4_128, sha},
+ {dhe_psk, '3des_ede_cbc', sha},
+ {dhe_psk, aes_128_cbc, sha},
+ {dhe_psk, aes_256_cbc, sha},
+ {rsa_psk, rc4_128, sha},
+ {rsa_psk, '3des_ede_cbc', sha},
+ {rsa_psk, aes_128_cbc, sha},
+ {rsa_psk, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
+
+psk_anon_suites() ->
[{psk, rc4_128, sha},
{psk, '3des_ede_cbc', sha},
{psk, aes_128_cbc, sha},
@@ -718,24 +843,29 @@ psk_suites() ->
{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}].
+ {dhe_psk, aes_256_cbc, sha}].
srp_suites() ->
+ Suites =
+ [{srp_anon, '3des_ede_cbc', sha},
+ {srp_rsa, '3des_ede_cbc', sha},
+ {srp_anon, aes_128_cbc, sha},
+ {srp_rsa, aes_128_cbc, sha},
+ {srp_anon, aes_256_cbc, sha},
+ {srp_rsa, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
+
+srp_anon_suites() ->
[{srp_anon, '3des_ede_cbc', sha},
- {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_anon, aes_256_cbc, sha}].
srp_dss_suites() ->
- [{srp_dss, '3des_ede_cbc', sha},
- {srp_dss, aes_128_cbc, sha},
- {srp_dss, aes_256_cbc, sha}].
+ Suites =
+ [{srp_dss, '3des_ede_cbc', sha},
+ {srp_dss, aes_128_cbc, sha},
+ {srp_dss, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
pem_to_der(File) ->
{ok, PemBin} = file:read_file(File),
@@ -747,7 +877,7 @@ der_to_pem(File, Entries) ->
cipher_result(Socket, Result) ->
Result = ssl:connection_info(Socket),
- ct:print("Successfull connect: ~p~n", [Result]),
+ ct:log("Successfull connect: ~p~n", [Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
ssl:send(Socket, "Hello\n"),
@@ -817,15 +947,11 @@ init_tls_version(Version) ->
ssl:start().
sufficient_crypto_support('tlsv1.2') ->
- Data = "Sampl",
- Data2 = "e #1",
- Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39,
- 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>,
- try
- crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- true
- catch _:_ -> false
- end;
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport));
+sufficient_crypto_support(ciphers_ec) ->
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport));
sufficient_crypto_support(_) ->
true.
@@ -858,3 +984,45 @@ send_recv_result_active_once(Socket) ->
{ssl, Socket, "Hello world"} ->
ok
end.
+
+is_sane_ecc(openssl) ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.0a" ++ _ -> % Known bug in openssl
+ %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
+ false;
+ "OpenSSL 1.0.0" ++ _ -> % Known bug in openssl
+ %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
+ false;
+ "OpenSSL 0.9.8" ++ _ -> % Does not support ECC
+ false;
+ "OpenSSL 0.9.7" ++ _ -> % Does not support ECC
+ false;
+ _ ->
+ true
+ end;
+is_sane_ecc(crypto) ->
+ [{_,_, Bin}] = crypto:info_lib(),
+ case binary_to_list(Bin) of
+ "OpenSSL 0.9.8" ++ _ -> % Does not support ECC
+ false;
+ "OpenSSL 0.9.7" ++ _ -> % Does not support ECC
+ false;
+ _ ->
+ true
+ end;
+is_sane_ecc(_) ->
+ true.
+
+cipher_restriction(Config0) ->
+ case is_sane_ecc(openssl) of
+ false ->
+ Opts = proplists:get_value(server_opts, Config0),
+ Config1 = proplists:delete(server_opts, Config0),
+ VerOpts = proplists:get_value(server_verification_opts, Config1),
+ Config = proplists:delete(server_verification_opts, Config1),
+ Restricted0 = ssl:cipher_suites() -- ecdsa_suites(),
+ Restricted = Restricted0 -- ecdh_rsa_suites(),
+ [{server_opts, [{ciphers, Restricted} | Opts]}, {server_verification_opts, [{ciphers, Restricted} | VerOpts] } | Config];
+ true ->
+ Config0
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index a3d382f837..7f91865a86 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -104,10 +104,11 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
- Config = ssl_test_lib:cert_options(Config1),
- [{watchdog, Dog} | Config]
+ Config2 = ssl_test_lib:cert_options(Config1),
+ Config = [{watchdog, Dog} | Config2],
+ ssl_test_lib:cipher_restriction(Config)
catch _:_ ->
{skip, "Crypto did not start"}
end
@@ -200,7 +201,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -212,7 +213,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -241,10 +242,10 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -272,7 +273,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -284,7 +285,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -314,10 +315,10 @@ erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -349,7 +350,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2 -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -362,7 +363,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -396,10 +397,10 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
" -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -431,11 +432,11 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -reconnect",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -467,7 +468,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -480,9 +481,9 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
delayed_send, [[ErlData, OpenSslData]]}},
{options, ClientOpts}]),
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, OpenSslData),
+ true = port_command(OpensslPort, OpenSslData),
ssl_test_lib:check_result(Client, ok),
@@ -516,7 +517,7 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -562,11 +563,11 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -597,7 +598,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -610,7 +611,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -640,7 +641,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -652,7 +653,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -691,10 +692,10 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -749,7 +750,7 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:rsa_suites(),
+ Ciphers = ssl_test_lib:rsa_suites(openssl),
run_suites(Ciphers, Version, Config, rsa).
%%--------------------------------------------------------------------
@@ -779,7 +780,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -793,7 +794,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
[{versions, [Version]} | ClientOpts]}]),
%% Send garbage
- port_command(OpensslPort, ?OPENSSL_GARBAGE),
+ true = port_command(OpensslPort, ?OPENSSL_GARBAGE),
ct:sleep(?SLEEP),
@@ -835,7 +836,7 @@ expired_session(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -893,10 +894,10 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost -ssl2 -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
receive
{'EXIT', OpenSslPort, _} ->
ok
@@ -912,7 +913,7 @@ erlang_client_openssl_server_npn() ->
erlang_client_openssl_server_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok)
end),
@@ -925,9 +926,9 @@ erlang_client_openssl_server_npn_renegotiate() ->
erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok)
end),
ok.
@@ -939,7 +940,7 @@ erlang_server_openssl_client_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -951,9 +952,9 @@ erlang_server_openssl_client_npn_renegotiate() ->
erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -962,7 +963,7 @@ erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_with_opts(Config, [],
"-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -975,7 +976,7 @@ erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
[{client_preferred_next_protocols,
{client, [<<"spdy/2">>], <<"http/1.1">>}}], "",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -985,7 +986,7 @@ erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], "",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -994,7 +995,7 @@ erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_with_opts(Config, [], "-nextprotoneg spdy/2",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -1020,13 +1021,13 @@ run_suites(Ciphers, Version, Config, Type) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
process_flag(trap_exit, true),
- ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Port = ssl_test_lib:inet_port(node()),
@@ -1036,7 +1037,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1052,19 +1053,19 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
[{ciphers,[CipherSuite]} |
ClientOpts]}]),
- port_command(OpenSslPort, "Hello\n"),
+ true = port_command(OpenSslPort, "Hello\n"),
receive
{Port, {data, _}} when is_port(Port) ->
ok
after 500 ->
- ct:print("Time out on openssl port, check that"
+ ct:log("Time out on openssl port, check that"
" the messages Hello and world are received"
" during close of port" , []),
ok
end,
- port_command(OpenSslPort, " world\n"),
+ true = port_command(OpenSslPort, " world\n"),
Result = ssl_test_lib:wait_for_result(Client, ok),
@@ -1100,7 +1101,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1139,7 +1140,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1177,7 +1178,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1206,7 +1207,7 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS
Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1225,7 +1226,7 @@ erlang_ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ok.
erlang_ssl_receive(Socket, Data) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, Data} ->
@@ -1247,7 +1248,7 @@ erlang_ssl_receive(Socket, Data) ->
connection_info(Socket, Version) ->
case ssl:connection_info(Socket) of
{ok, {Version, _} = Info} ->
- ct:print("Connection info: ~p~n", [Info]),
+ ct:log("Connection info: ~p~n", [Info]),
ok;
{ok, {OtherVersion, _}} ->
{wrong_version, OtherVersion}
@@ -1269,28 +1270,28 @@ close_port(Port) ->
close_loop(Port, Time, SentClose) ->
receive
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("openssl ~s~n",[Debug]),
close_loop(Port, Time, SentClose);
{ssl,_,Msg} ->
- io:format("ssl Msg ~s~n",[Msg]),
+ ct:log("ssl Msg ~s~n",[Msg]),
close_loop(Port, Time, SentClose);
{Port, closed} ->
- io:format("Port Closed~n",[]),
+ ct:log("Port Closed~n",[]),
ok;
{'EXIT', Port, Reason} ->
- io:format("Port Closed ~p~n",[Reason]),
+ ct:log("Port Closed ~p~n",[Reason]),
ok;
Msg ->
- io:format("Port Msg ~p~n",[Msg]),
+ ct:log("Port Msg ~p~n",[Msg]),
close_loop(Port, Time, SentClose)
after Time ->
case SentClose of
false ->
- io:format("Closing port ~n",[]),
+ ct:log("Closing port ~n",[]),
catch erlang:port_close(Port),
close_loop(Port, Time, true);
true ->
- io:format("Timeout~n",[])
+ ct:log("Timeout~n",[])
end
end.
@@ -1305,7 +1306,7 @@ server_sent_garbage(Socket) ->
wait_for_openssl_server() ->
receive
{Port, {data, Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("openssl ~s~n",[Debug]),
%% openssl has started make sure
%% it will be in accept. Parsing
%% output is too error prone. (Even
diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml
index b6c0fa4e05..1aff78f4fc 100644
--- a/lib/stdlib/doc/src/lists.xml
+++ b/lib/stdlib/doc/src/lists.xml
@@ -152,6 +152,31 @@
</desc>
</func>
<func>
+ <name name="filtermap" arity="2"/>
+ <fsummary>Filter and map elements which satisfy a function</fsummary>
+ <desc>
+ <p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>)</c> on successive elements <c>Elem</c>
+ of <c><anno>List1</anno></c>. <c><anno>Fun</anno>/2</c> must return either a boolean
+ or a tuple <c>{true, <anno>Value</anno>}</c>. The function returns the list of elements
+ for which <c><anno>Fun</anno></c> returns a new value, where a value of <c>true</c>
+ is synonymous with <c>{true, <anno>Elem</anno>}</c>.</p>
+ <p>That is, <c>filtermap</c> behaves as if it had been defined as follows:</p>
+ <code type="none">
+filtermap(Fun, List1) ->
+ lists:foldr(fun(Elem, Acc) ->
+ case Fun(Elem) of
+ false -> Acc;
+ true -> [Elem|Acc];
+ {true,Value} -> [Value|Acc]
+ end,
+ end, [], List1).</code>
+ <p>Example:</p>
+ <pre>
+> <input>lists:filtermap(fun(X) -> case X rem 2 of 0 -> {true, X div 2}; _ -> false end end, [1,2,3,4,5]).</input>
+[1,2]</pre>
+ </desc>
+ </func>
+ <func>
<name name="flatlength" arity="1"/>
<fsummary>Length of flattened deep list</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index c5d476e54b..1f64b38554 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -625,6 +625,7 @@ Eshell V5.10.1 (abort with ^G)
</section>
<section>
<title>Unicode File Names</title>
+ <marker id="unicode_file_names"/>
<p>Most modern operating systems support Unicode file names in some
way or another. There are several different ways to do this and
Erlang by default treats the different approaches differently:</p>
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index fe7e0f8e60..2e9ebece0e 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -302,10 +302,10 @@ clear_crypto_key_fun() ->
-spec make_crypto_key(mode(), string()) ->
{binary(), binary(), binary(), binary()}.
-make_crypto_key(des3_cbc, String) ->
+make_crypto_key(des3_cbc=Type, String) ->
<<K1:8/binary,K2:8/binary>> = First = erlang:md5(String),
<<K3:8/binary,IVec:8/binary>> = erlang:md5([First|reverse(String)]),
- {K1,K2,K3,IVec}.
+ {Type,[K1,K2,K3],IVec,8}.
%%
%% Local functions
@@ -864,20 +864,20 @@ mandatory_chunks() ->
-define(CRYPTO_KEY_SERVER, beam_lib__crypto_key_server).
-decrypt_abst(Mode, Module, File, Id, AtomTable, Bin) ->
+decrypt_abst(Type, Module, File, Id, AtomTable, Bin) ->
try
- KeyString = get_crypto_key({debug_info, Mode, Module, File}),
- Key = make_crypto_key(des3_cbc, KeyString),
- Term = decrypt_abst_1(Mode, Key, Bin),
+ KeyString = get_crypto_key({debug_info, Type, Module, File}),
+ Key = make_crypto_key(Type, KeyString),
+ Term = decrypt_abst_1(Key, Bin),
{AtomTable, {Id, Term}}
catch
_:_ ->
error({key_missing_or_invalid, File, Id})
end.
-decrypt_abst_1(des3_cbc, {K1, K2, K3, IVec}, Bin) ->
+decrypt_abst_1({Type,Key,IVec,_BlockSize}, Bin) ->
ok = start_crypto(),
- NewBin = crypto:des3_cbc_decrypt(K1, K2, K3, IVec, Bin),
+ NewBin = crypto:block_decrypt(Type, Key, IVec, Bin),
binary_to_term(NewBin).
start_crypto() ->
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index 45aef0ea80..50812cc532 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -1246,13 +1246,8 @@ req(Proc, R) ->
{'DOWN', Ref, process, Proc, _Info} ->
badarg;
{Proc, Reply} ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, process, Proc, _Reason} ->
- Reply
- after 0 ->
- Reply
- end
+ erlang:demonitor(Ref, [flush]),
+ Reply
end.
%% Inlined.
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 0a1caa7178..d1d060ebc8 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -601,7 +601,7 @@ enter_file2(NewF, Pname, From, St0, AtLocation) ->
%% file will depend on the order of file inclusions in the parent files
Path = [filename:dirname(Pname) | tl(St0#epp.path)],
_ = set_encoding(NewF),
- #epp{file=NewF,location=Loc,name=Pname,delta=0,
+ #epp{file=NewF,location=Loc,name=Pname,name2=Pname,delta=0,
sstk=[St0|St0#epp.sstk],path=Path,macs=Ms}.
enter_file_reply(From, Name, Location, AtLocation) ->
@@ -1339,8 +1339,7 @@ epp_reply(From, Rep) ->
wait_epp_reply(Epp, Mref) ->
receive
{epp_reply,Epp,Rep} ->
- erlang:demonitor(Mref),
- receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
Rep;
{'DOWN',Mref,_,_,E} ->
receive {epp_reply,Epp,Rep} -> Rep
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 7c7566e4ec..c0596e5ba6 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -35,7 +35,7 @@
| fun((Expr :: erl_parse:abstract_expr(),
CurrentIndentation :: integer(),
CurrentPrecedence :: non_neg_integer(),
- HookFunction :: hook_function()) ->
+ Options :: options()) ->
io_lib:chars())).
-type(option() :: {hook, hook_function()}
@@ -225,7 +225,7 @@ lattribute(module, {M,Vs}, _Opts, _State) ->
lattribute(module, M, _Opts, _State) ->
attr("module", [{var,0,pname(M)}]);
lattribute(export, Falist, _Opts, _State) ->
- call({var,0,"-export"}, [falist(Falist)], 0, none);
+ call({var,0,"-export"}, [falist(Falist)], 0, options(none));
lattribute(import, Name, _Opts, _State) when is_list(Name) ->
attr("import", [{var,0,pname(Name)}]);
lattribute(import, {From,Falist}, _Opts, _State) ->
@@ -240,10 +240,10 @@ lattribute(Name, Arg, #options{encoding = Encoding}, _State) ->
typeattr(Tag, {TypeName,Type,Args}, _Opts) ->
{first,leaf("-"++atom_to_list(Tag)++" "),
- typed(call({atom,0,TypeName}, Args, 0, none), Type)}.
+ typed(call({atom,0,TypeName}, Args, 0, options(none)), Type)}.
ltype({ann_type,_Line,[V,T]}) ->
- typed(lexpr(V, none), T);
+ typed(lexpr(V, options(none)), T);
ltype({paren_type,_Line,[T]}) ->
[$(,ltype(T),$)];
ltype({type,_Line,union,Ts}) ->
@@ -253,7 +253,7 @@ ltype({type,_Line,list,[T]}) ->
ltype({type,_Line,nonempty_list,[T]}) ->
{seq,$[,$],[$,],[ltype(T),leaf("...")]};
ltype({type,Line,nil,[]}) ->
- lexpr({nil,Line}, 0, none);
+ lexpr({nil,Line}, 0, options(none));
ltype({type,Line,tuple,any}) ->
simple_type({atom,Line,tuple}, []);
ltype({type,_Line,tuple,Ts}) ->
@@ -261,7 +261,7 @@ ltype({type,_Line,tuple,Ts}) ->
ltype({type,_Line,record,[{atom,_,N}|Fs]}) ->
record_type(N, Fs);
ltype({type,_Line,range,[_I1,_I2]=Es}) ->
- expr_list(Es, '..', fun lexpr/2, none);
+ expr_list(Es, '..', fun lexpr/2, options(none));
ltype({type,_Line,binary,[I1,I2]}) ->
binary_type(I1, I2); % except binary()
ltype({type,_Line,'fun',[]}) ->
@@ -277,14 +277,14 @@ ltype({remote_type,Line,[M,F,Ts]}) ->
ltype({atom,_,T}) ->
leaf(write(T));
ltype(E) ->
- lexpr(E, 0, none).
+ lexpr(E, 0, options(none)).
binary_type(I1, I2) ->
B = [[] || {integer,_,0} <- [I1]] =:= [],
U = [[] || {integer,_,0} <- [I2]] =:= [],
P = max_prec(),
- E1 = [[leaf("_:"),lexpr(I1, P, none)] || B],
- E2 = [[leaf("_:_*"),lexpr(I2, P, none)] || U],
+ E1 = [[leaf("_:"),lexpr(I1, P, options(none))] || B],
+ E2 = [[leaf("_:_*"),lexpr(I2, P, options(none))] || U],
{seq,'<<','>>',[$,],E1++E2}.
record_type(Name, Fields) ->
@@ -294,7 +294,7 @@ field_types(Fs) ->
tuple_type(Fs, fun field_type/1).
field_type({type,_Line,field_type,[Name,Type]}) ->
- typed(lexpr(Name, none), Type).
+ typed(lexpr(Name, options(none)), Type).
typed(B, {type,_,union,Ts}) ->
%% Special layout for :: followed by union.
@@ -330,7 +330,8 @@ sig_type(FunType) ->
fun_type([], FunType).
guard_type(Before, Gs) ->
- Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, none)}]},
+ Opts = options(none),
+ Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, Opts)}]},
{list,[{step,Before,Gl}]}.
constraint({type,_Line,constraint,[Tag,As]}, _Opts) ->
@@ -345,7 +346,7 @@ type_args({type,_line,product,Ts}) ->
targs(Ts).
simple_type(Tag, Types) ->
- {first,lexpr(Tag, 0, none),targs(Types)}.
+ {first,lexpr(Tag, 0, options(none)),targs(Types)}.
targs(Ts) ->
{seq,$(,$),[$,],ltypes(Ts)}.
@@ -357,7 +358,7 @@ ltypes(Ts, F) ->
[F(T) || T <- Ts].
attr(Name, Args) ->
- call({var,0,format("-~s", [Name])}, Args, 0, none).
+ call({var,0,format("-~s", [Name])}, Args, 0, options(none)).
pname(['' | As]) ->
[$. | pname(As)];
@@ -632,11 +633,11 @@ bit_elem_types([T | Rest]) ->
[bit_elem_type(T), $-|bit_elem_types(Rest)].
bit_elem_type({A,B}) ->
- [lexpr(erl_parse:abstract(A), none),
+ [lexpr(erl_parse:abstract(A), options(none)),
$:,
- lexpr(erl_parse:abstract(B), none)];
+ lexpr(erl_parse:abstract(B), options(none))];
bit_elem_type(T) ->
- lexpr(erl_parse:abstract(T), none).
+ lexpr(erl_parse:abstract(T), options(none)).
%% end of BITS
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 9c4b95acf6..30a81ade49 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -472,11 +472,11 @@ rec_nodes(Tag, [{N,R}|Tail], Name, Badnodes, Replies, Time, TimerId ) ->
{'DOWN', R, _, _, _} ->
rec_nodes(Tag, Tail, Name, [N|Badnodes], Replies, Time, TimerId);
{{Tag, N}, Reply} -> %% Tag is bound !!!
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes(Tag, Tail, Name, Badnodes,
[{N,Reply}|Replies], Time, TimerId);
{timeout, TimerId, _} ->
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
%% Collect all replies that already have arrived
rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies)
end;
@@ -527,10 +527,10 @@ rec_nodes_rest(Tag, [{N,R}|Tail], Name, Badnodes, Replies) ->
{'DOWN', R, _, _, _} ->
rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies);
{{Tag, N}, Reply} -> %% Tag is bound !!!
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N,Reply}|Replies])
after 0 ->
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies)
end;
rec_nodes_rest(Tag, [N|Tail], Name, Badnodes, Replies) ->
@@ -572,16 +572,6 @@ start_monitor(Node, Name) when is_atom(Node), is_atom(Name) ->
end
end.
-%% Cancels a monitor started with Ref=erlang:monitor(_, _).
-unmonitor(Ref) when is_reference(Ref) ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, _, _, _} ->
- true
- after 0 ->
- true
- end.
-
%%% ---------------------------------------------------
%%% Message handling functions
%%% ---------------------------------------------------
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index c92e9e3ade..53728237ca 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -598,11 +598,7 @@ default_output() ->
wait_io_mon_reply(From, Mref) ->
receive
{io_reply, From, Reply} ->
- erlang:demonitor(Mref),
- receive
- {'DOWN', Mref, _, _, _} -> true
- after 0 -> true
- end,
+ erlang:demonitor(Mref, [flush]),
Reply;
{'EXIT', From, _What} ->
receive
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index 961c060019..0c033acd88 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -36,7 +36,7 @@
-export([merge/3, rmerge/3, sort/2, umerge/3, rumerge/3, usort/2]).
-export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2,
- partition/2,zf/2,
+ partition/2,zf/2,filtermap/2,
mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2,
split/2]).
@@ -1291,18 +1291,28 @@ partition(Pred, [H | T], As, Bs) ->
partition(Pred, [], As, Bs) when is_function(Pred, 1) ->
{reverse(As), reverse(Bs)}.
--spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)].
+-spec filtermap(Fun, List1) -> List2 when
+ Fun :: fun((Elem) -> boolean() | {'true', Value}),
+ List1 :: [Elem],
+ List2 :: [Elem | Value],
+ Elem :: term(),
+ Value :: term().
-zf(F, [Hd|Tail]) ->
+filtermap(F, [Hd|Tail]) ->
case F(Hd) of
true ->
- [Hd|zf(F, Tail)];
+ [Hd|filtermap(F, Tail)];
{true,Val} ->
- [Val|zf(F, Tail)];
+ [Val|filtermap(F, Tail)];
false ->
- zf(F, Tail)
+ filtermap(F, Tail)
end;
-zf(F, []) when is_function(F, 1) -> [].
+filtermap(F, []) when is_function(F, 1) -> [].
+
+-spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)].
+
+zf(F, L) ->
+ filtermap(F, L).
-spec foreach(Fun, List) -> ok when
Fun :: fun((Elem :: T) -> term()),
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index a4f4035c79..42a42b7fd7 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -66,6 +66,183 @@ obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
{deprecated, {rpc, multi_server_call, A}};
+%% *** CRYPTO add in R16B01 ***
+
+obsolete_1(crypto, md4, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, md5, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, sha, 1) ->
+ {deprecated, {crypto, hash, 2}};
+
+obsolete_1(crypto, md4_init, 0) ->
+ {deprecated, {crypto, hash_init, 1}};
+obsolete_1(crypto, md5_init, 0) ->
+ {deprecated, {crypto, hash_init, 1}};
+obsolete_1(crypto, sha_init, 0) ->
+ {deprecated, {crypto, hash_init, 1}};
+
+obsolete_1(crypto, md4_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, md5_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, sha_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+
+obsolete_1(crypto, md4_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, md5_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, sha_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+
+obsolete_1(crypto, md5_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+obsolete_1(crypto, sha_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+obsolete_1(crypto, sha_mac, 3) ->
+ {deprecated, {crypto, hmac, 4}};
+
+obsolete_1(crypto, sha_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+obsolete_1(crypto, md5_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+
+obsolete_1(crypto, rsa_sign, 2) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, rsa_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, rsa_verify, 3) ->
+ {deprecated, {crypto, verify, 5}};
+obsolete_1(crypto, rsa_verify, 4) ->
+ {deprecated, {crypto, verify, 5}};
+
+obsolete_1(crypto, dss_sign, 2) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, dss_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+
+obsolete_1(crypto, dss_verify, 3) ->
+ {deprecated, {crypto, verify, 4}};
+obsolete_1(crypto, dss_verify, 4) ->
+ {deprecated, {crypto, verify, 4}};
+
+obsolete_1(crypto, mod_exp, 3) ->
+ {deprecated, {crypto, mod_pow, 3}};
+
+obsolete_1(crypto, dh_compute_key, 3) ->
+ {deprecated, {crypto, compute_key, 4}};
+obsolete_1(crypto, dh_generate_key, 1) ->
+ {deprecated, {crypto, generate_key, 3}};
+obsolete_1(crypto, dh_generate_key, 2) ->
+ {deprecated, {crypto, generate_key, 3}};
+
+obsolete_1(crypto, des_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_ecb_encrypt, 2) ->
+ {deprecated, {crypto, block_encrypt, 3}};
+obsolete_1(crypto, des_ede3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_cfb_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cfb_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_encrypt, 2) ->
+ {deprecated, {crypto, block_encrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cbc_128_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+
+obsolete_1(crypto, des_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_ecb_decrypt, 2) ->
+ {deprecated, {crypto, block_decrypt, 3}};
+obsolete_1(crypto, des_ede3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_cfb_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cfb_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_decrypt, 2) ->
+ {deprecated, {crypto, block_decrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cbc_128_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+
+obsolete_1(crypto, aes_ctr_stream_decrypt, 2) ->
+ {deprecated, {crypto, stream_decrypt, 2}};
+obsolete_1(crypto, aes_ctr_stream_encrypt, 2) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, aes_ctr_decrypt, 3) ->
+ {deprecated, {crypto, stream_decrypt, 2}};
+obsolete_1(crypto, aes_ctr_encrypt, 3) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, rc4_encrypt, 2) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, rc4_encrypt_with_state, 2) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, aes_ctr_stream_init, 2) ->
+ {deprecated, {crypto, stream_init, 3}};
+obsolete_1(crypto, rc4_set_key, 1) ->
+ {deprecated, {crypto, stream_init, 2}};
+
+obsolete_1(crypto, rsa_private_decrypt, 3) ->
+ {deprecated, {crypto, private_decrypt, 4}};
+obsolete_1(crypto, rsa_public_decrypt, 3) ->
+ {deprecated, {crypto, public_decrypt, 4}};
+obsolete_1(crypto, rsa_private_encrypt, 3) ->
+ {deprecated, {crypto, private_encrypt, 4}};
+obsolete_1(crypto, rsa_public_encrypt, 3) ->
+ {deprecated, {crypto, public_encrypt, 4}};
+
+obsolete_1(crypto, des_cfb_ivec, 2) ->
+ {deprecated, {crypto, next_iv, 3}};
+obsolete_1(crypto,des_cbc_ivec, 1) ->
+ {deprecated, {crypto, next_iv, 2}};
+obsolete_1(crypto, aes_cbc_ivec, 1) ->
+ {deprecated, {crypto, next_iv, 2}};
+
+obsolete_1(crypto,info, 0) ->
+ {deprecated, {crypto, module_info, 0}};
+
+obsolete_1(crypto, strong_rand_mpint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, erlint, 1) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, mpint, 1) ->
+ {deprecated, "needed only by deprecated functions"};
+
+
%% *** SNMP ***
obsolete_1(snmp, N, A) ->
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 9f93747c3e..54328cd9ff 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -63,7 +63,9 @@
%%--------------------------------------------------------------------------
-record(child, {% pid is undefined when child is not running
- pid = undefined :: child() | {restarting,pid()} | [pid()],
+ pid = undefined :: child()
+ | {restarting, pid() | undefined}
+ | [pid()],
name :: child_id(),
mfargs :: mfargs(),
restart_type :: restart(),
@@ -752,6 +754,9 @@ restart(Child, State) ->
end,
timer:apply_after(0,?MODULE,try_again_restart,[self(),Id]),
{ok,NState2};
+ {try_again, NState2, #child{name=ChName}} ->
+ timer:apply_after(0,?MODULE,try_again_restart,[self(),ChName]),
+ {ok,NState2};
Other ->
Other
end;
@@ -798,10 +803,16 @@ restart(rest_for_one, Child, State) ->
case start_children(ChAfter2, State#state.name) of
{ok, ChAfter3} ->
{ok, State#state{children = ChAfter3 ++ ChBefore}};
- {error, ChAfter3, _Reason} ->
+ {error, ChAfter3, {failed_to_start_child, ChName, _Reason}}
+ when ChName =:= Child#child.name ->
NChild = Child#child{pid=restarting(Child#child.pid)},
NState = State#state{children = ChAfter3 ++ ChBefore},
- {try_again, replace_child(NChild,NState)}
+ {try_again, replace_child(NChild,NState)};
+ {error, ChAfter3, {failed_to_start_child, ChName, _Reason}} ->
+ NChild = lists:keyfind(ChName, #child.name, ChAfter3),
+ NChild2 = NChild#child{pid=?restarting(undefined)},
+ NState = State#state{children = ChAfter3 ++ ChBefore},
+ {try_again, replace_child(NChild2,NState), NChild2}
end;
restart(one_for_all, Child, State) ->
Children1 = del_child(Child#child.pid, State#state.children),
@@ -809,10 +820,16 @@ restart(one_for_all, Child, State) ->
case start_children(Children2, State#state.name) of
{ok, NChs} ->
{ok, State#state{children = NChs}};
- {error, NChs, _Reason} ->
+ {error, NChs, {failed_to_start_child, ChName, _Reason}}
+ when ChName =:= Child#child.name ->
NChild = Child#child{pid=restarting(Child#child.pid)},
NState = State#state{children = NChs},
- {try_again, replace_child(NChild,NState)}
+ {try_again, replace_child(NChild,NState)};
+ {error, NChs, {failed_to_start_child, ChName, _Reason}} ->
+ NChild = lists:keyfind(ChName, #child.name, NChs),
+ NChild2 = NChild#child{pid=?restarting(undefined)},
+ NState = State#state{children = NChs},
+ {try_again, replace_child(NChild2,NState), NChild2}
end.
restarting(Pid) when is_pid(Pid) -> ?restarting(Pid);
diff --git a/lib/stdlib/src/timer.erl b/lib/stdlib/src/timer.erl
index 689e42051f..e11fb046e9 100644
--- a/lib/stdlib/src/timer.erl
+++ b/lib/stdlib/src/timer.erl
@@ -354,7 +354,7 @@ timer_timeout(SysTime) ->
'$end_of_table' ->
infinity;
{Time, _Ref} when Time > SysTime ->
- Timeout = (Time - SysTime) div 1000,
+ Timeout = (Time - SysTime + 999) div 1000,
%% Returned timeout must fit in a small int
erlang:min(Timeout, ?MAX_TIMEOUT);
Key ->
@@ -414,7 +414,7 @@ next_timeout() ->
'$end_of_table' ->
infinity;
{Time, _} ->
- erlang:min(positive((Time - system_time()) div 1000), ?MAX_TIMEOUT)
+ erlang:min(positive((Time - system_time() + 999) div 1000), ?MAX_TIMEOUT)
end.
%% Help functions
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 6aa09d7bd0..af82f22b21 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -66,6 +66,7 @@ MODULES= \
string_SUITE \
supervisor_1 \
supervisor_2 \
+ supervisor_3 \
supervisor_deadlock \
naughty_child \
shell_SUITE \
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index b2f1aa955a..0cbdf76270 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -104,6 +104,8 @@ include_local(suite) ->
include_local(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
?line File = filename:join(DataDir, "include_local.erl"),
+ FooHrl = filename:join([DataDir,"include","foo.hrl"]),
+ BarHrl = filename:join([DataDir,"include","bar.hrl"]),
%% include_local.erl includes include/foo.hrl which
%% includes bar.hrl (also in include/) without requiring
%% any additional include path, and overriding any file
@@ -111,6 +113,8 @@ include_local(Config) when is_list(Config) ->
?line {ok, List} = epp:parse_file(File, [DataDir], []),
?line {value, {attribute,_,a,{true,true}}} =
lists:keysearch(a,3,List),
+ [{File,1},{FooHrl,1},{BarHrl,1},{FooHrl,5},{File,5}] =
+ [ FileLine || {attribute,_,file,FileLine} <- List ],
ok.
%%% Here is a little reimplementation of epp:parse_file, which times out
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 7ff4c81ea6..18ec17a4bf 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -992,7 +993,7 @@ otp_10622(Config) when is_list(Config) ->
<<0>>),
check(fun() -> <<"\x{aa}ff"/utf8>> = <<"\x{aa}ff"/utf8>> end,
"<<\"\\x{aa}ff\"/utf8>> = <<\"\\x{aa}ff\"/utf8>>. ",
- <<"�\xaaff">>),
+ <<"Â\xaaff">>),
%% The same bug as last example:
check(fun() -> case <<"foo"/utf8>> of
<<"foo"/utf8>> -> true
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 9c0a43abcc..ff3470349e 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -49,7 +49,7 @@
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
- otp_10302/1, otp_10820/1]).
+ otp_10302/1, otp_10820/1, otp_11100/1]).
%% Internal export.
-export([ehook/6]).
@@ -81,7 +81,7 @@ groups() ->
{tickets, [],
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
otp_8473, otp_8522, otp_8567, otp_8664, otp_9147,
- otp_10302, otp_10820]}].
+ otp_10302, otp_10820, otp_11100]}].
init_per_suite(Config) ->
Config.
@@ -1103,6 +1103,45 @@ file_attr_is_string("-file(\"" ++ _) -> true;
file_attr_is_string([_ | L]) ->
file_attr_is_string(L).
+otp_11100(doc) ->
+ "OTP-11100. Fix printing of invalid forms.";
+otp_11100(suite) -> [];
+otp_11100(Config) when is_list(Config) ->
+ %% There are a few places where the added code ("options(none)")
+ %% doesn't make a difference (pp:bit_elem_type/1 is an example).
+
+ %% Cannot trigger the use of the hook function with export/import.
+ "-export([{fy,a}/b]).\n" =
+ pf({attribute,1,export,[{{fy,a},b}]}),
+ "-type foo() :: integer(INVALID-FORM:{foo,bar}:).\n" =
+ pf({attribute,1,type,{foo,{type,1,integer,[{foo,bar}]},[]}}),
+ pf({attribute,1,type,
+ {a,{type,1,range,[{integer,1,1},{foo,bar}]},[]}}),
+ "-type foo(INVALID-FORM:{foo,bar}:) :: A.\n" =
+ pf({attribute,1,type,{foo,{var,1,'A'},[{foo,bar}]}}),
+ "-type foo() :: (INVALID-FORM:{foo,bar}: :: []).\n" =
+ pf({attribute,1,type,
+ {foo,{paren_type,1,
+ [{ann_type,1,[{foo,bar},{type,1,nil,[]}]}]},
+ []}}),
+ "-type foo() :: <<_:INVALID-FORM:{foo,bar}:>>.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,binary,[{foo,bar},{integer,1,0}]},[]}}),
+ "-type foo() :: <<_:10, _:_*INVALID-FORM:{foo,bar}:>>.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,binary,[{integer,1,10},{foo,bar}]},[]}}),
+ "-type foo() :: #r{INVALID-FORM:{foo,bar}: :: integer()}.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,record,
+ [{atom,1,r},
+ {type,1,field_type,
+ [{foo,bar},{type,1,integer,[]}]}]},
+ []}}),
+ ok.
+
+pf(Form) ->
+ lists:flatten(erl_pp:form(Form,none)).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index af5d5a8f21..bd69019892 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -75,6 +75,7 @@
-export([otp_9932/1]).
-export([otp_9423/1]).
-export([otp_10182/1]).
+-export([memory_check_summary/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
@@ -149,7 +150,9 @@ all() ->
give_away, setopts, bad_table, types,
otp_10182,
otp_9932,
- otp_9423].
+ otp_9423,
+
+ memory_check_summary]. % MUST BE LAST
groups() ->
[{new, [],
@@ -185,7 +188,8 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
stop_spawn_logger(),
- catch erts_debug:set_internal_state(available_internal_state, false).
+ catch erts_debug:set_internal_state(available_internal_state, false),
+ ok.
init_per_group(_GroupName, Config) ->
Config.
@@ -193,6 +197,26 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+%% Test that we did not have "too many" failed verify_etsmem()'s
+%% in the test suite.
+%% verify_etsmem() may give a low number of false positives
+%% as concurrent activities, such as lingering processes
+%% from earlier test suites, may do unrelated ets (de)allocations.
+memory_check_summary(_Config) ->
+ case whereis(ets_test_spawn_logger) of
+ undefined ->
+ ?t:fail("No spawn logger exist");
+ _ ->
+ ets_test_spawn_logger ! {self(), get_failed_memchecks},
+ receive {get_failed_memchecks, FailedMemchecks} -> ok end,
+ io:format("Failed memchecks: ~p\n",[FailedMemchecks]),
+ if FailedMemchecks > 3 ->
+ ct:fail("Too many failed (~p) memchecks", [FailedMemchecks]);
+ true ->
+ ok
+ end
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5635,7 +5659,8 @@ verify_etsmem({MemInfo,AllTabs}) ->
io:format("Actual: ~p", [MemInfo2]),
io:format("Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
io:format("Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
- ?t:fail()
+ ets_test_spawn_logger ! failed_memcheck,
+ {comment, "Failed memory check"}
end.
@@ -5657,10 +5682,10 @@ stop_loopers(Loopers) ->
looper(Fun, State) ->
looper(Fun, Fun(State)).
-spawn_logger(Procs) ->
+spawn_logger(Procs, FailedMemchecks) ->
receive
{new_test_proc, Proc} ->
- spawn_logger([Proc|Procs]);
+ spawn_logger([Proc|Procs], FailedMemchecks);
{sync_test_procs, Kill, From} ->
lists:foreach(fun (Proc) when From == Proc ->
ok;
@@ -5683,7 +5708,14 @@ spawn_logger(Procs) ->
end
end, Procs),
From ! test_procs_synced,
- spawn_logger([From])
+ spawn_logger([From], FailedMemchecks);
+
+ failed_memcheck ->
+ spawn_logger(Procs, FailedMemchecks+1);
+
+ {Pid, get_failed_memchecks} ->
+ Pid ! {get_failed_memchecks, FailedMemchecks},
+ spawn_logger(Procs, FailedMemchecks)
end.
pid_status(Pid) ->
@@ -5699,7 +5731,7 @@ start_spawn_logger() ->
case whereis(ets_test_spawn_logger) of
Pid when is_pid(Pid) -> true;
_ -> register(ets_test_spawn_logger,
- spawn_opt(fun () -> spawn_logger([]) end,
+ spawn_opt(fun () -> spawn_logger([], 0) end,
[{priority, max}]))
end.
@@ -5710,8 +5742,7 @@ start_spawn_logger() ->
stop_spawn_logger() ->
Mon = erlang:monitor(process, ets_test_spawn_logger),
(catch exit(whereis(ets_test_spawn_logger), kill)),
- receive {'DOWN', Mon, _, _, _} -> ok end,
- ok.
+ receive {'DOWN', Mon, _, _, _} -> ok end.
wait_for_test_procs() ->
wait_for_test_procs(false).
@@ -5811,7 +5842,7 @@ spawn_monitor_with_pid(Pid, Fun, N) ->
end) of
Pid ->
{Pid, erlang:monitor(process, Pid)};
- Other ->
+ _Other ->
spawn_monitor_with_pid(Pid,Fun,N-1)
end.
@@ -6117,11 +6148,18 @@ repeat_for_opts(F, OptGenList) ->
repeat_for_opts(F, OptGenList, []).
repeat_for_opts(F, [], Acc) ->
- lists:map(fun(Opts) ->
- OptList = lists:filter(fun(E) -> E =/= void end, Opts),
- io:format("Calling with options ~p\n",[OptList]),
- F(OptList)
- end, Acc);
+ lists:foldl(fun(Opts, RV_Acc) ->
+ OptList = lists:filter(fun(E) -> E =/= void end, Opts),
+ io:format("Calling with options ~p\n",[OptList]),
+ RV = F(OptList),
+ case RV_Acc of
+ {comment,_} -> RV_Acc;
+ _ -> case RV of
+ {comment,_} -> RV;
+ _ -> [RV | RV_Acc]
+ end
+ end
+ end, [], Acc);
repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) ->
repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]);
repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index 3b6a3f38bc..a360a0809b 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.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
@@ -1082,13 +1082,23 @@ replace_state(Config) when is_list(Config) ->
%% 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) ->
+ case test_server:is_native(gen) of
+ true ->
+ {skip,
+ "gen is native - huge message queue optimization "
+ "is not implemented"};
+ false ->
+ do_call_with_huge_message_queue()
+ end.
+
+do_call_with_huge_message_queue() ->
?line Pid = spawn_link(fun echo_loop/0),
- ?line {Time,ok} = tc(fun() -> calls(10, Pid) end),
+ ?line {Time,ok} = tc(fun() -> calls(10000, Pid) end),
?line [self() ! {msg,N} || N <- lists:seq(1, 500000)],
erlang:garbage_collect(),
- ?line {NewTime,ok} = tc(fun() -> calls(10, Pid) end),
+ ?line {NewTime,ok} = tc(fun() -> calls(10000, Pid) end),
io:format("Time for empty message queue: ~p", [Time]),
io:format("Time for huge message queue: ~p", [NewTime]),
diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl
index b56f0b39d8..cd7210f8ec 100644
--- a/lib/stdlib/test/lists_SUITE.erl
+++ b/lib/stdlib/test/lists_SUITE.erl
@@ -2532,8 +2532,8 @@ otp_5939(Config) when is_list(Config) ->
?line [] = lists:filter(Pred, []),
?line {'EXIT', _} = (catch lists:partition(func, [])),
?line {[],[]} = lists:partition(Pred, []),
- ?line {'EXIT', _} = (catch lists:zf(func, [])),
- ?line [] = lists:zf(Fun1, []),
+ ?line {'EXIT', _} = (catch lists:filtermap(func, [])),
+ ?line [] = lists:filtermap(Fun1, []),
?line {'EXIT', _} = (catch lists:foreach(func, [])),
?line ok = lists:foreach(Fun1, []),
?line {'EXIT', _} = (catch lists:mapfoldl(func, [], [])),
diff --git a/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl b/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl
index e0db132c47..b93b907392 100644
--- a/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl
+++ b/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -515,7 +516,7 @@ create_handle() ->
$.:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
@@ -523,16 +524,16 @@ create_handle() ->
$-:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$-:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ä:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
@@ -541,19 +542,19 @@ create_handle() ->
$\026:8/integer-unit:1-unsigned-big,
$%:8/integer-unit:1-unsigned-big,
$r:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¥:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$F:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ :8/integer-unit:1-unsigned-big,
+ $ð:8/integer-unit:1-unsigned-big,
$":8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $³:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $þ:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $É:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
@@ -562,7 +563,7 @@ create_handle() ->
$<:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
@@ -570,16 +571,16 @@ create_handle() ->
$-:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$-:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ä:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Î:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
@@ -588,22 +589,22 @@ create_handle() ->
$\026:8/integer-unit:1-unsigned-big,
$%:8/integer-unit:1-unsigned-big,
$r:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¥:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$::8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¡:8/integer-unit:1-unsigned-big,
+ $ð:8/integer-unit:1-unsigned-big,
$":8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ñ:8/integer-unit:1-unsigned-big,
$Y:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ª:8/integer-unit:1-unsigned-big,
$9:8/integer-unit:1-unsigned-big,
$\r:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $ý:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
@@ -612,51 +613,51 @@ create_handle() ->
$I:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$/:8/integer-unit:1-unsigned-big,
$H:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ä:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¶:8/integer-unit:1-unsigned-big,
+ $µ:8/integer-unit:1-unsigned-big,
+ $²:8/integer-unit:1-unsigned-big,
+ $Í:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ò:8/integer-unit:1-unsigned-big,
$e:8/integer-unit:1-unsigned-big,
$\211:8/integer-unit:1-unsigned-big,
$E:8/integer-unit:1-unsigned-big,
$\s:8/integer-unit:1-unsigned-big,
$>:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $£:8/integer-unit:1-unsigned-big,
$\023:8/integer-unit:1-unsigned-big,
$\210:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ç:8/integer-unit:1-unsigned-big,
$\232:8/integer-unit:1-unsigned-big,
$\226:8/integer-unit:1-unsigned-big,
$\223:8/integer-unit:1-unsigned-big,
$\237:8/integer-unit:1-unsigned-big,
$X:8/integer-unit:1-unsigned-big,
$\222:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$\235:8/integer-unit:1-unsigned-big,
$l:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¨:8/integer-unit:1-unsigned-big,
$g:8/integer-unit:1-unsigned-big,
$i:8/integer-unit:1-unsigned-big,
$d:8/integer-unit:1-unsigned-big,
$\200:8/integer-unit:1-unsigned-big,
$\001:8/integer-unit:1-unsigned-big,
$R:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $µ:8/integer-unit:1-unsigned-big,
$\r:8/integer-unit:1-unsigned-big,
$\214:8/integer-unit:1-unsigned-big,
$\030:8/integer-unit:1-unsigned-big,
@@ -664,7 +665,7 @@ create_handle() ->
$\000:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$c:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ö:8/integer-unit:1-unsigned-big,
$\017:8/integer-unit:1-unsigned-big,
$=:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
@@ -708,24 +709,24 @@ create_handle() ->
$*:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$/:8/integer-unit:1-unsigned-big,
$H:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ä:8/integer-unit:1-unsigned-big,
$\005:8/integer-unit:1-unsigned-big,
$R:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¶:8/integer-unit:1-unsigned-big,
+ $¶:8/integer-unit:1-unsigned-big,
$\031:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$\f:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$e:8/integer-unit:1-unsigned-big,
$\211:8/integer-unit:1-unsigned-big,
$E:8/integer-unit:1-unsigned-big,
@@ -737,7 +738,7 @@ create_handle() ->
$/:8/integer-unit:1-unsigned-big,
$\022:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$\205:8/integer-unit:1-unsigned-big,
$\t:8/integer-unit:1-unsigned-big,
$\216:8/integer-unit:1-unsigned-big>>,
@@ -749,33 +750,33 @@ create_handle() ->
$j:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Î:8/integer-unit:1-unsigned-big,
+ $Ï:8/integer-unit:1-unsigned-big,
$+:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ú:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $·:8/integer-unit:1-unsigned-big,
$\f:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $æ:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ö:8/integer-unit:1-unsigned-big,
$\222:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ò:8/integer-unit:1-unsigned-big,
$\202:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ô:8/integer-unit:1-unsigned-big,
$D:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $®:8/integer-unit:1-unsigned-big,
$\034:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
@@ -791,7 +792,7 @@ create_handle() ->
$W:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$\003:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $£:8/integer-unit:1-unsigned-big,
$\023:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$/:8/integer-unit:1-unsigned-big,
@@ -800,18 +801,18 @@ create_handle() ->
$\027:8/integer-unit:1-unsigned-big,
$\237:8/integer-unit:1-unsigned-big,
$\205:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¤:8/integer-unit:1-unsigned-big,
$\227:8/integer-unit:1-unsigned-big,
$\007:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¤:8/integer-unit:1-unsigned-big,
$\227:8/integer-unit:1-unsigned-big,
$\021:8/integer-unit:1-unsigned-big,
$.:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ï:8/integer-unit:1-unsigned-big,
$\003:8/integer-unit:1-unsigned-big,
$\224:8/integer-unit:1-unsigned-big,
$\217:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$\002:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\203:8/integer-unit:1-unsigned-big,
@@ -1398,7 +1399,7 @@ lookup_handle() ->
$.:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
@@ -1406,16 +1407,16 @@ lookup_handle() ->
$-:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$-:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
@@ -1424,19 +1425,19 @@ lookup_handle() ->
$\026:8/integer-unit:1-unsigned-big,
$%:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¦:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$F:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ :8/integer-unit:1-unsigned-big,
+ $ð:8/integer-unit:1-unsigned-big,
$":8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $³:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\206:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $Þ:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
@@ -1445,7 +1446,7 @@ lookup_handle() ->
$.:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
@@ -1453,16 +1454,16 @@ lookup_handle() ->
$-:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$-:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
@@ -1471,19 +1472,19 @@ lookup_handle() ->
$\026:8/integer-unit:1-unsigned-big,
$%:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¦:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$F:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ :8/integer-unit:1-unsigned-big,
+ $ð:8/integer-unit:1-unsigned-big,
+ $â:8/integer-unit:1-unsigned-big,
+ $³:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\222:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $ä:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$h:8/integer-unit:1-unsigned-big,
$\003:8/integer-unit:1-unsigned-big,
@@ -1525,25 +1526,25 @@ lookup_handle() ->
$+:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$/:8/integer-unit:1-unsigned-big,
$H:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¶:8/integer-unit:1-unsigned-big,
+ $µ:8/integer-unit:1-unsigned-big,
+ $²:8/integer-unit:1-unsigned-big,
+ $Í:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ò:8/integer-unit:1-unsigned-big,
$e:8/integer-unit:1-unsigned-big,
$\211:8/integer-unit:1-unsigned-big,
$E:8/integer-unit:1-unsigned-big,
@@ -1555,10 +1556,10 @@ lookup_handle() ->
$/:8/integer-unit:1-unsigned-big,
$\022:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $×:8/integer-unit:1-unsigned-big,
$\227:8/integer-unit:1-unsigned-big,
$\t:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $Û:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
@@ -1567,33 +1568,33 @@ lookup_handle() ->
$\\:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Î:8/integer-unit:1-unsigned-big,
+ $Ï:8/integer-unit:1-unsigned-big,
$+:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ú:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $û:8/integer-unit:1-unsigned-big,
$\f:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $æ:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ö:8/integer-unit:1-unsigned-big,
$\222:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ò:8/integer-unit:1-unsigned-big,
$\202:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ô:8/integer-unit:1-unsigned-big,
$D:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Á:8/integer-unit:1-unsigned-big,
$\034:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
@@ -1605,7 +1606,7 @@ lookup_handle() ->
$Y:8/integer-unit:1-unsigned-big,
$b:8/integer-unit:1-unsigned-big,
$Q:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¢:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$\003:8/integer-unit:1-unsigned-big,
@@ -1616,7 +1617,7 @@ lookup_handle() ->
$>:8/integer-unit:1-unsigned-big,
$\v:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $µ:8/integer-unit:1-unsigned-big,
$\020:8/integer-unit:1-unsigned-big,
$H:8/integer-unit:1-unsigned-big,
$5:8/integer-unit:1-unsigned-big,
@@ -1630,7 +1631,7 @@ lookup_handle() ->
$\005:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ù:8/integer-unit:1-unsigned-big,
$\031:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big>>}
end,
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index 681c154463..3c49aaa103 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -2820,7 +2821,7 @@ otp_10302(Config) when is_list(Config) ->
"ok.\n** exception error: an error occurred when evaluating"
" an arithmetic expression\n in operator '/'/2\n"
- " called as <<\"�\">> / <<\"�\">>.\n" = t({Node,Test7}),
+ " called as <<\"ª\">> / <<\"ª\">>.\n" = t({Node,Test7}),
Test8 =
<<"begin
A = [1089],
diff --git a/lib/stdlib/test/supervisor_3.erl b/lib/stdlib/test/supervisor_3.erl
new file mode 100644
index 0000000000..31b3037d6f
--- /dev/null
+++ b/lib/stdlib/test/supervisor_3.erl
@@ -0,0 +1,45 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2011. 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%
+%%
+%% Description: Simulates the behaviour that a child process may have.
+%% Is used by the supervisor_SUITE test suite.
+-module(supervisor_3).
+
+-export([start_child/2, init/1]).
+
+-export([handle_call/3, handle_info/2, terminate/2]).
+
+start_child(Name, Caller) ->
+ gen_server:start_link(?MODULE, [Name, Caller], []).
+
+init([Name, Caller]) ->
+ Caller ! {Name, self()},
+ receive
+ {Result, Caller} ->
+ Result
+ end.
+
+handle_call(Req, _From, State) ->
+ {reply, Req, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, Time) ->
+ timer:sleep(Time),
+ ok.
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index 569c66959e..ff5be6bb95 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -53,9 +53,10 @@
%% Restart strategy tests
-export([ one_for_one/1,
one_for_one_escalation/1, one_for_all/1,
- one_for_all_escalation/1,
+ one_for_all_escalation/1, one_for_all_other_child_fails_restart/1,
simple_one_for_one/1, simple_one_for_one_escalation/1,
rest_for_one/1, rest_for_one_escalation/1,
+ rest_for_one_other_child_fails_restart/1,
simple_one_for_one_extra/1, simple_one_for_one_shutdown/1]).
%% Misc tests
@@ -107,12 +108,14 @@ groups() ->
{restart_one_for_one, [],
[one_for_one, one_for_one_escalation]},
{restart_one_for_all, [],
- [one_for_all, one_for_all_escalation]},
+ [one_for_all, one_for_all_escalation,
+ one_for_all_other_child_fails_restart]},
{restart_simple_one_for_one, [],
[simple_one_for_one, simple_one_for_one_shutdown,
simple_one_for_one_extra, simple_one_for_one_escalation]},
{restart_rest_for_one, [],
- [rest_for_one, rest_for_one_escalation]}].
+ [rest_for_one, rest_for_one_escalation,
+ rest_for_one_other_child_fails_restart]}].
init_per_suite(Config) ->
Config.
@@ -879,6 +882,57 @@ one_for_all_escalation(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+%% Test that the supervisor terminates a restarted child when a different
+%% child fails to start.
+one_for_all_other_child_fails_restart(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ Self = self(),
+ Child1 = {child1, {supervisor_3, start_child, [child1, Self]},
+ permanent, 1000, worker, []},
+ Child2 = {child2, {supervisor_3, start_child, [child2, Self]},
+ permanent, 1000, worker, []},
+ Children = [Child1, Child2],
+ StarterFun = fun() ->
+ {ok, SupPid} = start_link({ok, {{one_for_all, 3, 3600}, Children}}),
+ Self ! {sup_pid, SupPid},
+ receive {stop, Self} -> ok end
+ end,
+ StarterPid = spawn_link(StarterFun),
+ Ok = {{ok, undefined}, Self},
+ %% Let the children start.
+ Child1Pid = receive {child1, Pid1} -> Pid1 end,
+ Child1Pid ! Ok,
+ Child2Pid = receive {child2, Pid2} -> Pid2 end,
+ Child2Pid ! Ok,
+ %% Supervisor started.
+ SupPid = receive {sup_pid, Pid} -> Pid end,
+ link(SupPid),
+ exit(Child1Pid, die),
+ %% Let child1 restart but don't let child2.
+ Child1Pid2 = receive {child1, Pid3} -> Pid3 end,
+ Child1Pid2Ref = erlang:monitor(process, Child1Pid2),
+ Child1Pid2 ! Ok,
+ Child2Pid2 = receive {child2, Pid4} -> Pid4 end,
+ Child2Pid2 ! {{stop, normal}, Self},
+ %% Check child1 is terminated.
+ receive
+ {'DOWN', Child1Pid2Ref, _, _, shutdown} ->
+ ok;
+ {_childName, _Pid} ->
+ exit(SupPid, kill),
+ check_exit([StarterPid, SupPid]),
+ test_server:fail({restarting_child_not_terminated, Child1Pid2})
+ end,
+ %% Let the restart complete.
+ Child1Pid3 = receive {child1, Pid5} -> Pid5 end,
+ Child1Pid3 ! Ok,
+ Child2Pid3 = receive {child2, Pid6} -> Pid6 end,
+ Child2Pid3 ! Ok,
+ StarterPid ! {stop, Self},
+ check_exit([StarterPid, SupPid]).
+
+
+%%-------------------------------------------------------------------------
%% Test the simple_one_for_one base case.
simple_one_for_one(Config) when is_list(Config) ->
process_flag(trap_exit, true),
@@ -1044,6 +1098,52 @@ rest_for_one_escalation(Config) when is_list(Config) ->
terminate(SupPid, CPid1, child1, abnormal),
check_exit([CPid2, SupPid]).
+
+%%-------------------------------------------------------------------------
+%% Test that the supervisor terminates a restarted child when a different
+%% child fails to start.
+rest_for_one_other_child_fails_restart(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ Self = self(),
+ Child1 = {child1, {supervisor_3, start_child, [child1, Self]},
+ permanent, 1000, worker, []},
+ Child2 = {child2, {supervisor_3, start_child, [child2, Self]},
+ permanent, 1000, worker, []},
+ Children = [Child1, Child2],
+ StarterFun = fun() ->
+ {ok, SupPid} = start_link({ok, {{rest_for_one, 3, 3600}, Children}}),
+ Self ! {sup_pid, SupPid},
+ receive {stop, Self} -> ok end
+ end,
+ StarterPid = spawn_link(StarterFun),
+ Ok = {{ok, undefined}, Self},
+ %% Let the children start.
+ Child1Pid = receive {child1, Pid1} -> Pid1 end,
+ Child1Pid ! Ok,
+ Child2Pid = receive {child2, Pid2} -> Pid2 end,
+ Child2Pid ! Ok,
+ %% Supervisor started.
+ SupPid = receive {sup_pid, Pid} -> Pid end,
+ link(SupPid),
+ exit(Child1Pid, die),
+ %% Let child1 restart but don't let child2.
+ Child1Pid2 = receive {child1, Pid3} -> Pid3 end,
+ Child1Pid2 ! Ok,
+ Child2Pid2 = receive {child2, Pid4} -> Pid4 end,
+ Child2Pid2 ! {{stop, normal}, Self},
+ %% Let child2 restart.
+ receive
+ {child2, Child2Pid3} ->
+ Child2Pid3 ! Ok;
+ {child1, _Child1Pid3} ->
+ exit(SupPid, kill),
+ check_exit([StarterPid, SupPid]),
+ test_server:fail({restarting_started_child, Child1Pid2})
+ end,
+ StarterPid ! {stop, Self},
+ check_exit([StarterPid, SupPid]).
+
+
%%-------------------------------------------------------------------------
%% Test that the supervisor does not hang forever if the child unliks
%% and then is terminated by the supervisor.
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl
index 7233c061ef..a57641ef62 100644
--- a/lib/stdlib/test/zip_SUITE.erl
+++ b/lib/stdlib/test/zip_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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
@@ -109,13 +109,32 @@ borderline_test(Size, TempDir) ->
ok.
unzip_list(Archive, Name) ->
- case os:find_executable("unzip") of
- Unzip when is_list(Unzip) ->
+ case unix_unzip_exists() of
+ true ->
unzip_list1(Archive, Name);
_ ->
ok
end.
+%% Used to do os:find_executable() to check if unzip exists, but on
+%% some hosts that would give an unzip program which did not take the
+%% "-Z" option.
+%% Here we check that "unzip -Z" (which should display usage) and
+%% check that it exists with status 0.
+unix_unzip_exists() ->
+ case os:type() of
+ {unix,_} ->
+ Port = open_port({spawn,"unzip -Z > /dev/null"}, [exit_status]),
+ receive
+ {Port,{exit_status,0}} ->
+ true;
+ {Port,{exit_status,_Fail}} ->
+ false
+ end;
+ _ ->
+ false
+ end.
+
unzip_list1(Archive, Name) ->
Expect = Name ++ "\n",
cmd_expect("unzip -Z -1 " ++ Archive, Expect).
diff --git a/lib/test_server/src/erl2html2.erl b/lib/test_server/src/erl2html2.erl
index 5584c1e50c..d0f40c47a7 100644
--- a/lib/test_server/src/erl2html2.erl
+++ b/lib/test_server/src/erl2html2.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -214,7 +215,7 @@ html_encoding(utf8) ->
%%% from the source.
%%%
%%% Example: if the encoding of the file is utf8, and we have a string
-%%% containing "�" = [229], then we need to convert this to [195,165]
+%%% containing "å" = [229], then we need to convert this to [195,165]
%%% before writing. Note that this conversion is only necessary
%%% because the destination file is not (necessarily) opened with utf8
%%% encoding - it is opened with default encoding in order to allow
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index 21c10adccb..ffa21d054c 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -1183,7 +1183,7 @@ init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels,
"<td>~.3fs</td><td><b>~ts</b></td><td>~w Ok, ~w Failed~ts of ~w</td></tr>\n"
"</tfoot>\n",
[Time,SuccessStr,OkN,FailedN,SkipStr,OkN+FailedN+SkippedN]),
- test_server_io:stop().
+ test_server_io:stop([major,html,unexpected_io]).
report_severe_error(Reason) ->
test_server_sup:framework_call(report, [severe_error,Reason]).
@@ -1588,7 +1588,7 @@ do_test_cases(TopCases, SkipCases,
print(major, "=started ~s",
[lists:flatten(timestamp_get(""))]),
- put(test_server_html_footer, Footer),
+ test_server_io:set_footer(Footer),
run_test_cases(TestSpec, Config, TimetrapData)
end;
diff --git a/lib/test_server/src/test_server_io.erl b/lib/test_server/src/test_server_io.erl
index a979deffc3..73d4468bda 100644
--- a/lib/test_server/src/test_server_io.erl
+++ b/lib/test_server/src/test_server_io.erl
@@ -29,7 +29,7 @@
%%
-module(test_server_io).
--export([start_link/0,stop/0,get_gl/1,set_fd/2,
+-export([start_link/0,stop/1,get_gl/1,set_fd/2,
start_transaction/0,end_transaction/0,
print_buffered/1,print/3,print_unexpected/1,
set_footer/1,set_job_name/1,set_gl_props/1]).
@@ -55,10 +55,10 @@ start_link() ->
Other
end.
-stop() ->
+stop(FilesToClose) ->
OldGL = group_leader(),
group_leader(self(), self()),
- req(stop),
+ req({stop,FilesToClose}),
group_leader(OldGL, self()),
ok.
@@ -213,12 +213,21 @@ handle_call({set_job_name,Name}, _From, St) ->
handle_call({set_gl_props,Props}, _From, #st{shared_gl=Shared}=St) ->
test_server_gl:set_props(Shared, Props),
{reply,ok,St#st{gl_props=Props}};
-handle_call(stop, From, #st{shared_gl=SGL,gls=Gls0}=St0) ->
+handle_call({stop,FdTags}, From, #st{fds=Fds,shared_gl=SGL,gls=Gls0}=St0) ->
St = St0#st{gls=gb_sets:insert(SGL, Gls0),stopping=From},
gc(St),
%% Give the users of the surviving group leaders some
%% time to finish.
erlang:send_after(2000, self(), stop_group_leaders),
+ %% close open log files
+ lists:foreach(fun(Tag) ->
+ case gb_trees:lookup(Tag, Fds) of
+ none ->
+ ok;
+ {value,Fd} ->
+ file:close(Fd)
+ end
+ end, FdTags),
{noreply,St}.
handle_info({'EXIT',Pid,normal}, #st{gls=Gls0,stopping=From}=St) ->
diff --git a/lib/test_server/test/test_server_SUITE.erl b/lib/test_server/test/test_server_SUITE.erl
index 3db2f5f9f1..8ad5fcfb5c 100644
--- a/lib/test_server/test/test_server_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -187,7 +188,7 @@ test_server_unicode(Config) ->
%% Create and run two test suites - one with filename and content
%% in latin1 (if the default filename mode is latin1) and one with
%% filename and content in utf8. Both have name and content
- %% including letters ���. Check that all logs are generated with
+ %% including letters äöå. Check that all logs are generated with
%% utf8 encoded filenames.
case file:native_name_encoding() of
utf8 ->
@@ -348,7 +349,7 @@ generate_and_run_unicode_test(Config0,Encoding) ->
SuiteHtml = translate_filename(LowerModStr++".src.html",Encoding),
true = filelib:is_regular(filename:join(RunDir,SuiteHtml)),
- TCLog = translate_filename(LowerModStr++".tc_���.html",Encoding),
+ TCLog = translate_filename(LowerModStr++".tc_äöå.html",Encoding),
true = filelib:is_regular(filename:join(RunDir,TCLog)),
ok.
@@ -370,7 +371,7 @@ start_node(Config,Name,Args) ->
end.
create_unicode_test_suite(Dir,Encoding) ->
- ModStr = "test_server_"++atom_to_list(Encoding)++"_���_SUITE",
+ ModStr = "test_server_"++atom_to_list(Encoding)++"_äöå_SUITE",
File = filename:join(Dir,ModStr++".erl"),
Suite =
["%% -*- ",epp:encoding_to_string(Encoding)," -*-\n",
@@ -378,12 +379,12 @@ create_unicode_test_suite(Dir,Encoding) ->
"\n"
"-export([all/1, init_per_suite/1, end_per_suite/1]).\n"
"-export([init_per_testcase/2, end_per_testcase/2]).\n"
- "-export([tc_���/1]).\n"
+ "-export([tc_äöå/1]).\n"
"\n"
"-include_lib(\"test_server/include/test_server.hrl\").\n"
"\n"
"all(suite) ->\n"
- " [tc_���].\n"
+ " [tc_äöå].\n"
"\n"
"init_per_suite(Config) ->\n"
" Config.\n"
@@ -406,7 +407,7 @@ create_unicode_test_suite(Dir,Encoding) ->
" ?t:timetrap_cancel(Dog),\n"
" ok.\n"
"\n"
- "tc_���(Config) when is_list(Config) ->\n"
+ "tc_äöå(Config) when is_list(Config) ->\n"
" true = filelib:is_dir(?config(priv_dir,Config)),\n"
" ok.\n"],
{ok,Fd} = file:open(raw_filename(File,Encoding),[write,{encoding,Encoding}]),
diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl
index 4cbb910f11..877218bda0 100644
--- a/lib/tools/src/fprof.erl
+++ b/lib/tools/src/fprof.erl
@@ -1226,10 +1226,7 @@ spawn_3step(Spawn, FunPrelude, FunAck, FunBody)
MRef = erlang:monitor(process, Parent),
receive
{Parent, Ref, Go} ->
- erlang:demonitor(MRef),
- receive {'DOWN', MRef, _, _, _} -> ok
- after 0 -> ok
- end,
+ erlang:demonitor(MRef, [flush]),
FunBody(Go);
{'DOWN', MRef, _, _, _} ->
ok
@@ -1238,8 +1235,7 @@ spawn_3step(Spawn, FunPrelude, FunAck, FunBody)
MRef = erlang:monitor(process, Child),
receive
{Child, Ref, Ack} ->
- erlang:demonitor(MRef),
- receive {'DOWN', MRef, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(MRef, [flush]),
try FunAck(Ack) of
{Result, Go} ->
catch Child ! {Parent, Ref, Go},
diff --git a/make/run_make.mk b/make/run_make.mk
index 1b4213107f..bb0da6743c 100644
--- a/make/run_make.mk
+++ b/make/run_make.mk
@@ -30,7 +30,7 @@ include $(ERL_TOP)/make/target.mk
.PHONY: valgrind
-opt debug purify quantify purecov valgrind gcov gprof lcnt:
+opt debug purify quantify purecov valgrind gcov gprof lcnt frmptr:
$(make_verbose)$(MAKE) -f $(TARGET)/Makefile TYPE=$@
plain smp frag smp_frag: