aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/doc/src/notes.xml31
-rw-r--r--lib/common_test/src/test_server.erl20
-rw-r--r--lib/common_test/test/ct_hooks_SUITE.erl44
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_fail_init_tc_SUITE.erl49
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_post_init_tc_cth.erl81
-rw-r--r--lib/crypto/c_src/Makefile.in2
-rw-r--r--lib/crypto/c_src/algorithms.c27
-rw-r--r--lib/crypto/c_src/atoms.c9
-rw-r--r--lib/crypto/c_src/atoms.h4
-rw-r--r--lib/crypto/c_src/cmac.c91
-rw-r--r--lib/crypto/c_src/cmac.h8
-rw-r--r--lib/crypto/c_src/crypto.c23
-rw-r--r--lib/crypto/c_src/hmac.c116
-rw-r--r--lib/crypto/c_src/hmac.h8
-rw-r--r--lib/crypto/c_src/mac.c718
-rw-r--r--lib/crypto/c_src/mac.h (renamed from lib/crypto/c_src/poly1305.h)18
-rw-r--r--lib/crypto/c_src/openssl_config.h6
-rw-r--r--lib/crypto/c_src/pkey.c5
-rw-r--r--lib/crypto/c_src/poly1305.c90
-rw-r--r--lib/crypto/doc/src/algorithm_details.xml288
-rw-r--r--lib/crypto/doc/src/crypto.xml386
-rw-r--r--lib/crypto/doc/src/new_api.xml181
-rw-r--r--lib/crypto/src/crypto.erl314
-rw-r--r--lib/crypto/test/crypto_SUITE.erl295
-rw-r--r--lib/dialyzer/doc/src/dialyzer.xml5
-rw-r--r--lib/dialyzer/src/dialyzer.hrl4
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl19
-rw-r--r--lib/dialyzer/src/dialyzer_cl_parse.erl4
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl4
-rw-r--r--lib/inets/src/http_server/httpd_request.erl4
-rw-r--r--lib/inets/test/http_format_SUITE.erl13
-rw-r--r--lib/kernel/doc/src/gen_udp.xml87
-rw-r--r--lib/kernel/doc/src/inet.xml50
-rw-r--r--lib/kernel/src/erts_debug.erl2
-rw-r--r--lib/kernel/src/gen_udp.erl75
-rw-r--r--lib/kernel/src/inet.erl16
-rw-r--r--lib/kernel/src/inet6_udp.erl23
-rw-r--r--lib/kernel/src/inet_udp.erl23
-rw-r--r--lib/kernel/src/local_udp.erl8
-rw-r--r--lib/kernel/src/user.erl3
-rw-r--r--lib/kernel/src/user_drv.erl37
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl6
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl155
-rw-r--r--lib/ssl/src/ssl_cipher.erl10
-rw-r--r--lib/ssl/src/ssl_handshake.erl5
-rw-r--r--lib/ssl/src/tls_v1.erl22
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl36
-rw-r--r--lib/tools/doc/src/notes.xml15
-rw-r--r--lib/wx/c_src/wxe_driver.c2
49 files changed, 2596 insertions, 846 deletions
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index a64818da7b..0b151b9d12 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -239,6 +239,37 @@
</section>
+<section><title>Common_Test 1.15.4.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If a ct hook is installed in the <c>suite/0</c> function
+ in a test suite, then the hook's <c>terminate/1</c>
+ function would be called several times without it's
+ <c>init/2</c> function being called first. This is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-15863 Aux Id: ERIERL-370 </p>
+ </item>
+ <item>
+ <p>
+ If <c>init_per_testcase</c> fails, the test itself is
+ skipped. According to the documentation, it should be
+ possible to change the result to failed in a hook
+ function. The only available hook function in this case
+ is <c>post_init_per_testcase</c>, but changing the return
+ value there did not affect the test case result. This is
+ now corrected.</p>
+ <p>
+ Own Id: OTP-15869 Aux Id: ERIERL-350 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.15.4.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/common_test/src/test_server.erl b/lib/common_test/src/test_server.erl
index 756cd4d692..588396f101 100644
--- a/lib/common_test/src/test_server.erl
+++ b/lib/common_test/src/test_server.erl
@@ -1364,23 +1364,29 @@ do_end_tc_call(Mod, IPTC={init_per_testcase,Func}, Res, Return) ->
{NOk,_} when NOk == auto_skip; NOk == fail;
NOk == skip ; NOk == skipped ->
{_,Args} = Res,
- IPTCEndRes =
+ {NewConfig,IPTCEndRes} =
case do_end_tc_call1(Mod, IPTC, Res, Return) of
IPTCEndConfig when is_list(IPTCEndConfig) ->
- IPTCEndConfig;
+ {IPTCEndConfig,IPTCEndConfig};
+ {failed,RetReason} when Return=:={fail,RetReason} ->
+ %% Fail reason not changed by framework or hook
+ {Args,Return};
+ {SF,_} = IPTCEndResult when SF=:=skip; SF=:=skipped;
+ SF=:=fail; SF=:=failed ->
+ {Args,IPTCEndResult};
_ ->
- Args
+ {Args,Return}
end,
EPTCInitRes =
case do_init_tc_call(Mod,{end_per_testcase_not_run,Func},
- IPTCEndRes,Return) of
+ NewConfig,IPTCEndRes) of
{ok,EPTCInitConfig} when is_list(EPTCInitConfig) ->
- {Return,EPTCInitConfig};
+ {IPTCEndRes,EPTCInitConfig};
_ ->
- {Return,IPTCEndRes}
+ {IPTCEndRes,NewConfig}
end,
do_end_tc_call1(Mod, {end_per_testcase_not_run,Func},
- EPTCInitRes, Return);
+ EPTCInitRes, IPTCEndRes);
_Ok ->
do_end_tc_call1(Mod, IPTC, Res, Return)
end;
diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl
index 08c18d91e2..b87464f5e4 100644
--- a/lib/common_test/test/ct_hooks_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE.erl
@@ -86,7 +86,7 @@ all(suite) ->
scope_suite_state_cth,
fail_pre_suite_cth, double_fail_pre_suite_cth,
fail_post_suite_cth, skip_pre_suite_cth, skip_pre_end_cth,
- skip_pre_init_tc_cth,
+ skip_pre_init_tc_cth, fail_post_init_tc_cth,
skip_post_suite_cth, recover_post_suite_cth, update_config_cth,
state_update_cth, update_result_cth, options_cth, same_id_cth,
fail_n_skip_with_minimal_cth, prio_cth, no_config,
@@ -206,6 +206,10 @@ skip_pre_init_tc_cth(Config) ->
do_test(skip_pre_init_tc_cth, "ct_cth_empty_SUITE.erl",
[skip_pre_init_tc_cth],Config).
+fail_post_init_tc_cth(Config) ->
+ do_test(fail_post_init_tc_cth, "ct_fail_init_tc_SUITE.erl",
+ [fail_post_init_tc_cth],Config).
+
recover_post_suite_cth(Config) when is_list(Config) ->
do_test(recover_post_suite_cth, "ct_cth_fail_per_suite_SUITE.erl",
[recover_post_suite_cth],Config).
@@ -1042,6 +1046,44 @@ test_events(skip_pre_init_tc_cth) ->
{?eh,stop_logging,[]}
];
+test_events(fail_post_init_tc_cth) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,init,['_',[]]}},
+ {?eh,start_info,{1,1,1}},
+ {?eh,tc_start,{ct_fail_init_tc_SUITE,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,[ct_fail_init_tc_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [ct_fail_init_tc_SUITE,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{ct_fail_init_tc_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{ct_fail_init_tc_SUITE,test_case}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [ct_fail_init_tc_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [ct_fail_init_tc_SUITE,test_case,'$proplist',
+ {skip,
+ {failed,
+ {ct_fail_init_tc_SUITE,init_per_testcase,
+ {{test_case_failed,"Failed in init_per_testcase"},'_'}}}},
+ []]}},
+ {?eh,tc_done,{ct_fail_init_tc_SUITE,test_case,
+ {failed,"Changed skip to fail in post_init_per_testcase"}}},
+ {?eh,cth,{empty_cth,on_tc_fail,
+ [ct_fail_init_tc_SUITE,test_case,
+ "Changed skip to fail in post_init_per_testcase",
+ []]}},
+ {?eh,test_stats,{0,1,{0,0}}},
+ {?eh,tc_start,{ct_fail_init_tc_SUITE,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,[ct_fail_init_tc_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,
+ [ct_fail_init_tc_SUITE,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_fail_init_tc_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
test_events(recover_post_suite_cth) ->
Suite = ct_cth_fail_per_suite_SUITE,
[
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_fail_init_tc_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_fail_init_tc_SUITE.erl
new file mode 100644
index 0000000000..96ddfc5782
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_fail_init_tc_SUITE.erl
@@ -0,0 +1,49 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ct_fail_init_tc_SUITE).
+
+-suite_defaults([{timetrap, {minutes, 10}}]).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("ct.hrl").
+
+%% Test server callback functions
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(TestCase, _Config) ->
+ ct:fail("Failed in init_per_testcase").
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [test_case].
+
+%% Test cases starts here.
+test_case(Config) when is_list(Config) ->
+ ok.
+
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_post_init_tc_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_post_init_tc_cth.erl
new file mode 100644
index 0000000000..ca9f05c40f
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_post_init_tc_cth.erl
@@ -0,0 +1,81 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-module(fail_post_init_tc_cth).
+
+
+-include_lib("common_test/src/ct_util.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+
+%% CT Hooks
+-compile(export_all).
+
+init(Id, Opts) ->
+ empty_cth:init(Id, Opts).
+
+pre_init_per_suite(Suite, Config, State) ->
+ empty_cth:pre_init_per_suite(Suite,Config,State).
+
+post_init_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_init_per_suite(Suite,Config,Return,State).
+
+pre_end_per_suite(Suite,Config,State) ->
+ empty_cth:pre_end_per_suite(Suite,Config,State).
+
+post_end_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_end_per_suite(Suite,Config,Return,State).
+
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
+
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
+
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
+
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
+
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
+
+post_init_per_testcase(Suite,TC,Config,{skip,_}=Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State),
+ {{fail,"Changed skip to fail in post_init_per_testcase"},State};
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
+
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
+
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
+
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
+
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
+
+terminate(State) ->
+ empty_cth:terminate(State).
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index b6a65d7488..2512013ed6 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -92,9 +92,9 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \
$(OBJDIR)/hash$(TYPEMARKER).o \
$(OBJDIR)/hmac$(TYPEMARKER).o \
$(OBJDIR)/info$(TYPEMARKER).o \
+ $(OBJDIR)/mac$(TYPEMARKER).o \
$(OBJDIR)/math$(TYPEMARKER).o \
$(OBJDIR)/pkey$(TYPEMARKER).o \
- $(OBJDIR)/poly1305$(TYPEMARKER).o \
$(OBJDIR)/rand$(TYPEMARKER).o \
$(OBJDIR)/rsa$(TYPEMARKER).o \
$(OBJDIR)/srp$(TYPEMARKER).o
diff --git a/lib/crypto/c_src/algorithms.c b/lib/crypto/c_src/algorithms.c
index 75cddeb1e9..53b8b7eaa9 100644
--- a/lib/crypto/c_src/algorithms.c
+++ b/lib/crypto/c_src/algorithms.c
@@ -20,13 +20,12 @@
#include "algorithms.h"
#include "cipher.h"
+#include "mac.h"
static unsigned int algo_hash_cnt, algo_hash_fips_cnt;
static ERL_NIF_TERM algo_hash[14]; /* increase when extending the list */
static unsigned int algo_pubkey_cnt, algo_pubkey_fips_cnt;
static ERL_NIF_TERM algo_pubkey[12]; /* increase when extending the list */
-static unsigned int algo_mac_cnt, algo_mac_fips_cnt;
-static ERL_NIF_TERM algo_mac[3]; /* increase when extending the list */
static unsigned int algo_curve_cnt, algo_curve_fips_cnt;
static ERL_NIF_TERM algo_curve[89]; /* increase when extending the list */
static unsigned int algo_rsa_opts_cnt, algo_rsa_opts_fips_cnt;
@@ -101,19 +100,6 @@ void init_algorithms_types(ErlNifEnv* env)
#endif
algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");
-
- // Validated algorithms first
- algo_mac_cnt = 0;
- algo_mac[algo_mac_cnt++] = enif_make_atom(env,"hmac");
-#ifdef HAVE_CMAC
- algo_mac[algo_mac_cnt++] = enif_make_atom(env,"cmac");
-#endif
-#ifdef HAVE_POLY1305
- algo_mac[algo_mac_cnt++] = enif_make_atom(env,"poly1305");
-#endif
- // Non-validated algorithms follow
- algo_mac_fips_cnt = algo_mac_cnt;
-
// Validated algorithms first
algo_curve_cnt = 0;
#if defined(HAVE_EC)
@@ -250,7 +236,6 @@ void init_algorithms_types(ErlNifEnv* env)
// Check that the max number of algos is updated
ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM));
ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM));
- ASSERT(algo_mac_cnt <= sizeof(algo_mac)/sizeof(ERL_NIF_TERM));
ASSERT(algo_curve_cnt <= sizeof(algo_curve)/sizeof(ERL_NIF_TERM));
ASSERT(algo_rsa_opts_cnt <= sizeof(algo_rsa_opts)/sizeof(ERL_NIF_TERM));
}
@@ -284,18 +269,12 @@ ERL_NIF_TERM cipher_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
return cipher_types_as_list(env); /* Exclude old api ciphers */
}
+
ERL_NIF_TERM mac_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- unsigned int cnt =
-#ifdef FIPS_SUPPORT
- FIPS_mode() ? algo_mac_fips_cnt :
-#endif
- algo_mac_cnt;
-
- return enif_make_list_from_array(env, algo_mac, cnt);
+ return mac_types_as_list(env);
}
-
ERL_NIF_TERM curve_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
unsigned int cnt =
diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c
index 059c14690f..bbeb329fa2 100644
--- a/lib/crypto/c_src/atoms.c
+++ b/lib/crypto/c_src/atoms.c
@@ -30,6 +30,10 @@ ERL_NIF_TERM atom_rsa_no_padding;
ERL_NIF_TERM atom_signature_md;
ERL_NIF_TERM atom_undefined;
+ERL_NIF_TERM atom_hmac;
+ERL_NIF_TERM atom_cmac;
+ERL_NIF_TERM atom_poly1305;
+
ERL_NIF_TERM atom_ok;
ERL_NIF_TERM atom_none;
ERL_NIF_TERM atom_notsup;
@@ -155,6 +159,11 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
atom_rsa_no_padding = enif_make_atom(env,"rsa_no_padding");
atom_signature_md = enif_make_atom(env,"signature_md");
atom_undefined = enif_make_atom(env,"undefined");
+
+ atom_hmac = enif_make_atom(env,"hmac");
+ atom_cmac = enif_make_atom(env,"cmac");
+ atom_poly1305 = enif_make_atom(env,"poly1305");
+
atom_ok = enif_make_atom(env,"ok");
atom_none = enif_make_atom(env,"none");
atom_notsup = enif_make_atom(env,"notsup");
diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h
index f5913de96f..0e2f1a0022 100644
--- a/lib/crypto/c_src/atoms.h
+++ b/lib/crypto/c_src/atoms.h
@@ -34,6 +34,10 @@ extern ERL_NIF_TERM atom_rsa_no_padding;
extern ERL_NIF_TERM atom_signature_md;
extern ERL_NIF_TERM atom_undefined;
+extern ERL_NIF_TERM atom_hmac;
+extern ERL_NIF_TERM atom_cmac;
+extern ERL_NIF_TERM atom_poly1305;
+
extern ERL_NIF_TERM atom_ok;
extern ERL_NIF_TERM atom_none;
extern ERL_NIF_TERM atom_notsup;
diff --git a/lib/crypto/c_src/cmac.c b/lib/crypto/c_src/cmac.c
index 49e67ccf29..a1564f6661 100644
--- a/lib/crypto/c_src/cmac.c
+++ b/lib/crypto/c_src/cmac.c
@@ -18,71 +18,56 @@
* %CopyrightEnd%
*/
-#include "cmac.h"
-#include "cipher.h"
+#include "common.h"
-ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Key, Data) */
-#if defined(HAVE_CMAC)
- const struct cipher_type_t *cipherp;
- const EVP_CIPHER *cipher;
- CMAC_CTX *ctx = NULL;
- ErlNifBinary key;
- ErlNifBinary data;
- ERL_NIF_TERM ret;
- size_t ret_size;
- unsigned char *outp;
- int cipher_len;
+/*****************************************************************
+ *
+ * This file has functions for compatibility with cryptolibs
+ * lacking the EVP_Digest API.
+ *
+ * See mac.c for the implementation using the EVP interface.
+ *
+ ****************************************************************/
- ASSERT(argc == 3);
+#if defined(HAVE_CMAC) && !defined(HAVE_EVP_PKEY_new_CMAC_key)
- if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
- goto bad_arg;
- if ((cipherp = get_cipher_type(argv[0], key.size)) == NULL)
- goto bad_arg;
- if (cipherp->flags & (NON_EVP_CIPHER | AEAD_CIPHER))
- goto bad_arg;
- if (!enif_inspect_iolist_as_binary(env, argv[2], &data))
- goto bad_arg;
+#include "cmac.h"
- if (FORBIDDEN_IN_FIPS(cipherp))
- return enif_raise_exception(env, atom_notsup);
- if ((cipher = cipherp->cipher.p) == NULL)
- return enif_raise_exception(env, atom_notsup);
+int cmac_low_level(ErlNifEnv* env,
+ ErlNifBinary key_bin, const EVP_CIPHER* cipher, ErlNifBinary text,
+ ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term)
+{
+ CMAC_CTX *ctx = NULL;
+ size_t size;
if ((ctx = CMAC_CTX_new()) == NULL)
- goto err;
- if (!CMAC_Init(ctx, key.data, key.size, cipher, NULL))
- goto err;
- if (!CMAC_Update(ctx, data.data, data.size))
- goto err;
- if ((cipher_len = EVP_CIPHER_block_size(cipher)) < 0)
- goto err;
- if ((outp = enif_make_new_binary(env, (size_t)cipher_len, &ret)) == NULL)
- goto err;
- if (!CMAC_Final(ctx, outp, &ret_size))
- goto err;
+ goto local_err;
- ASSERT(ret_size == (unsigned)EVP_CIPHER_block_size(cipher));
- CONSUME_REDS(env, data);
- goto done;
+ if (!CMAC_Init(ctx, key_bin.data, key_bin.size, cipher, NULL))
+ goto local_err;
- bad_arg:
- return enif_make_badarg(env);
+ if (!CMAC_Update(ctx, text.data, text.size))
+ goto local_err;
- err:
- ret = atom_notsup;
+ if ((size = (size_t)EVP_CIPHER_block_size(cipher)) < 0)
+ goto local_err;
- done:
+ if (!enif_alloc_binary(size, ret_bin))
+ goto local_err;
+ *ret_bin_alloc = 1;
+
+ if (!CMAC_Final(ctx, ret_bin->data, &ret_bin->size))
+ goto local_err;
+
+ CMAC_CTX_free(ctx);
+ return 1;
+
+ local_err:
if (ctx)
CMAC_CTX_free(ctx);
- return ret;
-#else
- /* The CMAC functionality was introduced in OpenSSL 1.0.1
- * Although OTP requires at least version 0.9.8, the versions 0.9.8 and 1.0.0 are
- * no longer maintained. */
- return atom_notsup;
-#endif
+ *return_term = EXCP_ERROR(env,"Compat cmac");
+ return 0;
}
+#endif
diff --git a/lib/crypto/c_src/cmac.h b/lib/crypto/c_src/cmac.h
index 14488def58..04c742b2dc 100644
--- a/lib/crypto/c_src/cmac.h
+++ b/lib/crypto/c_src/cmac.h
@@ -23,6 +23,12 @@
#include "common.h"
-ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+#if defined(HAVE_CMAC) && !defined(HAVE_EVP_PKEY_new_CMAC_key)
+
+int cmac_low_level(ErlNifEnv* env,
+ ErlNifBinary key_bin, const EVP_CIPHER* cipher, ErlNifBinary text,
+ ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term);
+
+#endif
#endif /* E_CMAC_H__ */
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index d533cba140..802818541b 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -31,7 +31,7 @@
#include "api_ng.h"
#include "bn.h"
#include "cipher.h"
-#include "cmac.h"
+#include "mac.h"
#include "dh.h"
#include "digest.h"
#include "dss.h"
@@ -46,7 +46,6 @@
#include "info.h"
#include "math.h"
#include "pkey.h"
-#include "poly1305.h"
#include "rand.h"
#include "rsa.h"
#include "srp.h"
@@ -74,13 +73,10 @@ static ErlNifFunc nif_funcs[] = {
{"hash_init_nif", 1, hash_init_nif, 0},
{"hash_update_nif", 2, hash_update_nif, 0},
{"hash_final_nif", 1, hash_final_nif, 0},
- {"hmac_nif", 3, hmac_nif, 0},
- {"hmac_nif", 4, hmac_nif, 0},
- {"hmac_init_nif", 2, hmac_init_nif, 0},
- {"hmac_update_nif", 2, hmac_update_nif, 0},
- {"hmac_final_nif", 1, hmac_final_nif, 0},
- {"hmac_final_nif", 2, hmac_final_nif, 0},
- {"cmac_nif", 3, cmac_nif, 0},
+ {"mac_nif", 4, mac_nif, 0},
+ {"mac_init_nif", 3, mac_init_nif, 0},
+ {"mac_update_nif", 2, mac_update_nif, 0},
+ {"mac_final_nif", 1, mac_final_nif, 0},
{"cipher_info_nif", 1, cipher_info_nif, 0},
{"aes_ige_crypt_nif", 4, aes_ige_crypt_nif, 0},
{"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0},
@@ -112,8 +108,6 @@ static ErlNifFunc nif_funcs[] = {
{"aead_cipher", 7, aead_cipher, 0},
- {"poly1305_nif", 2, poly1305_nif, 0},
-
{"engine_by_id_nif", 1, engine_by_id_nif, 0},
{"engine_init_nif", 1, engine_init_nif, 0},
{"engine_finish_nif", 1, engine_finish_nif, 0},
@@ -181,9 +175,15 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
if (!enif_inspect_binary(env, tpl_array[1], &lib_bin))
return __LINE__;
+#ifdef HAS_EVP_PKEY_CTX
+ if (!init_mac_ctx(env)) {
+ return __LINE__;
+ }
+#else
if (!init_hmac_ctx(env)) {
return __LINE__;
}
+#endif
if (!init_hash_ctx(env)) {
return __LINE__;
}
@@ -248,6 +248,7 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
#endif /* OPENSSL_THREADS */
init_digest_types(env);
+ init_mac_types(env);
init_cipher_types(env);
init_algorithms_types(env);
diff --git a/lib/crypto/c_src/hmac.c b/lib/crypto/c_src/hmac.c
index ff7005d75e..5e2c68bfee 100644
--- a/lib/crypto/c_src/hmac.c
+++ b/lib/crypto/c_src/hmac.c
@@ -18,6 +18,18 @@
* %CopyrightEnd%
*/
+
+/*****************************************************************
+ *
+ * This file has functions for compatibility with cryptolibs
+ * lacking the EVP_Digest API.
+ *
+ * See mac.c for the implementation using the EVP interface.
+ *
+ ****************************************************************/
+
+#ifndef HAS_EVP_PKEY_CTX
+
#include "hmac.h"
#include "digest.h"
@@ -47,61 +59,6 @@ int init_hmac_ctx(ErlNifEnv *env) {
return 0;
}
-ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Key, Data) or (Type, Key, Data, MacSize) */
- struct digest_type_t *digp = NULL;
- ErlNifBinary key, data;
- unsigned char buff[EVP_MAX_MD_SIZE];
- unsigned size = 0, req_size = 0;
- ERL_NIF_TERM ret;
- unsigned char *outp;
-
- ASSERT(argc == 3 || argc == 4);
-
- if ((digp = get_digest_type(argv[0])) == NULL)
- goto bad_arg;
- if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
- goto bad_arg;
- if (key.size > INT_MAX)
- goto bad_arg;
- if (!enif_inspect_iolist_as_binary(env, argv[2], &data))
- goto bad_arg;
- if (argc == 4) {
- if (!enif_get_uint(env, argv[3], &req_size))
- goto bad_arg;
- }
-
- if (digp->md.p == NULL)
- goto err;
- if (HMAC(digp->md.p,
- key.data, (int)key.size,
- data.data, data.size,
- buff, &size) == NULL)
- goto err;
-
- ASSERT(0 < size && size <= EVP_MAX_MD_SIZE);
- CONSUME_REDS(env, data);
-
- if (argc == 4) {
- if (req_size > size)
- goto bad_arg;
-
- size = req_size;
- }
-
- if ((outp = enif_make_new_binary(env, size, &ret)) == NULL)
- goto err;
-
- memcpy(outp, buff, size);
- return ret;
-
- bad_arg:
- return enif_make_badarg(env);
-
- err:
- return atom_notsup;
-}
-
static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj)
{
if (obj == NULL)
@@ -118,17 +75,17 @@ static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj)
}
ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Key) */
+{/* (hmac, Type, Key) */
struct digest_type_t *digp = NULL;
ErlNifBinary key;
ERL_NIF_TERM ret;
struct hmac_context *obj = NULL;
- ASSERT(argc == 2);
+ ASSERT(argc == 3);
- if ((digp = get_digest_type(argv[0])) == NULL)
+ if ((digp = get_digest_type(argv[1])) == NULL)
goto bad_arg;
- if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &key))
goto bad_arg;
if (key.size > INT_MAX)
goto bad_arg;
@@ -268,3 +225,44 @@ ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return ret;
}
+
+
+int hmac_low_level(ErlNifEnv* env, const EVP_MD *md,
+ ErlNifBinary key_bin, ErlNifBinary text,
+ ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term)
+{
+ unsigned int size_int;
+ size_t size;
+
+ /* Find the needed space */
+ if (HMAC(md,
+ key_bin.data, (int)key_bin.size,
+ text.data, text.size,
+ NULL, &size_int) == NULL)
+ {
+ *return_term = EXCP_ERROR(env, "Get HMAC size failed");
+ return 0;
+ }
+
+ size = (size_t)size_int; /* Otherwise "size" is unused in 0.9.8.... */
+ if (!enif_alloc_binary(size, ret_bin))
+ {
+ *return_term = EXCP_ERROR(env, "Alloc binary");
+ return 0;
+ }
+ *ret_bin_alloc = 1;
+
+ /* And do the real HMAC calc */
+ if (HMAC(md,
+ key_bin.data, (int)key_bin.size,
+ text.data, text.size,
+ ret_bin->data, &size_int) == NULL)
+ {
+ *return_term = EXCP_ERROR(env, "HMAC sign failed");
+ return 0;
+ }
+
+ return 1;
+}
+
+#endif
diff --git a/lib/crypto/c_src/hmac.h b/lib/crypto/c_src/hmac.h
index 1f0e0ca632..f5805e13e5 100644
--- a/lib/crypto/c_src/hmac.h
+++ b/lib/crypto/c_src/hmac.h
@@ -21,13 +21,19 @@
#ifndef E_HMAC_H__
#define E_HMAC_H__ 1
+#ifndef HAS_EVP_PKEY_CTX
+
#include "common.h"
int init_hmac_ctx(ErlNifEnv *env);
-ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+int hmac_low_level(ErlNifEnv* env, const EVP_MD *md,
+ ErlNifBinary key_bin, ErlNifBinary text,
+ ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term);
+#endif
+
#endif /* E_HMAC_H__ */
diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c
new file mode 100644
index 0000000000..8b2710b91a
--- /dev/null
+++ b/lib/crypto/c_src/mac.c
@@ -0,0 +1,718 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2019. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "common.h"
+#include "cipher.h"
+#include "digest.h"
+#include "cmac.h"
+#include "hmac.h"
+#include "mac.h"
+
+/***************************
+ MAC type declaration
+***************************/
+
+struct mac_type_t {
+ union {
+ const char* str; /* before init, NULL for end-of-table */
+ ERL_NIF_TERM atom; /* after init, 'false' for end-of-table */
+ }name;
+ union {
+ const int pkey_type;
+ }alg;
+ int type;
+ size_t key_len; /* != 0 to also match on key_len */
+};
+
+#define NO_mac 0
+#define HMAC_mac 1
+#define CMAC_mac 2
+#define POLY1305_mac 3
+
+static struct mac_type_t mac_types[] =
+{
+ {{"poly1305"},
+#ifdef HAVE_POLY1305
+ /* If we have POLY then we have EVP_PKEY */
+ {EVP_PKEY_POLY1305}, POLY1305_mac, 32
+#else
+ {EVP_PKEY_NONE}, NO_mac, 0
+#endif
+ },
+
+ {{"hmac"},
+#ifdef HAS_EVP_PKEY_CTX
+ {EVP_PKEY_HMAC}, HMAC_mac, 0
+#else
+ /* HMAC is always supported, but possibly with low-level routines */
+ {EVP_PKEY_NONE}, HMAC_mac, 0
+#endif
+ },
+
+ {{"cmac"},
+#ifdef HAVE_CMAC
+ /* If we have CMAC then we have EVP_PKEY */
+ {EVP_PKEY_CMAC}, CMAC_mac, 0
+#else
+ {EVP_PKEY_NONE}, NO_mac, 0
+#endif
+ },
+
+ /*==== End of list ==== */
+ {{NULL},
+ {0}, NO_mac, 0
+ }
+};
+
+
+/***************************
+ Mandatory prototypes
+***************************/
+
+struct mac_type_t* get_mac_type(ERL_NIF_TERM type, size_t key_len);
+struct mac_type_t* get_mac_type_no_key(ERL_NIF_TERM type);
+
+ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+ERL_NIF_TERM mac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+
+/********************************
+ Support functions for type array
+*********************************/
+
+void init_mac_types(ErlNifEnv* env)
+{
+ struct mac_type_t* p = mac_types;
+
+ for (p = mac_types; p->name.str; p++) {
+ p->name.atom = enif_make_atom(env, p->name.str);
+ }
+ p->name.atom = atom_false; /* end marker */
+}
+
+
+ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env)
+{
+ struct mac_type_t* p;
+ ERL_NIF_TERM prev, hd;
+
+ hd = enif_make_list(env, 0);
+ prev = atom_undefined;
+
+ for (p = mac_types; (p->name.atom & (p->name.atom != atom_false)); p++) {
+ if (prev == p->name.atom)
+ continue;
+
+ if (p->type != NO_mac)
+ {
+ hd = enif_make_list_cell(env, p->name.atom, hd);
+ }
+ }
+
+ return hd;
+}
+
+struct mac_type_t* get_mac_type(ERL_NIF_TERM type, size_t key_len)
+{
+ struct mac_type_t* p = NULL;
+ for (p = mac_types; p->name.atom != atom_false; p++) {
+ if (type == p->name.atom) {
+ if ((p->key_len == 0) || (p->key_len == key_len))
+ return p;
+ }
+ }
+ return NULL;
+}
+
+struct mac_type_t* get_mac_type_no_key(ERL_NIF_TERM type)
+{
+ struct mac_type_t* p = NULL;
+ for (p = mac_types; p->name.atom != atom_false; p++) {
+ if (type == p->name.atom) {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************
+ *
+ * Mac nif
+ *
+ ******************************************************************/
+ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (MacType, SubType, Key, Text) */
+ ErlNifBinary text;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[3], &text))
+ return EXCP_BADARG(env, "Bad text");
+
+ if (text.size > INT_MAX)
+ return EXCP_BADARG(env, "Too long text");
+
+ /* Run long jobs on a dirty scheduler to not block the current emulator thread */
+ if (text.size > MAX_BYTES_TO_NIF) {
+ return enif_schedule_nif(env, "mac_one_time",
+ ERL_NIF_DIRTY_JOB_CPU_BOUND,
+ mac_one_time, argc, argv);
+ }
+
+ return mac_one_time(env, argc, argv);
+}
+
+
+
+ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (MacType, SubType, Key, Text) */
+
+ struct mac_type_t *macp;
+ ErlNifBinary key_bin, text;
+ int ret_bin_alloc = 0;
+ ERL_NIF_TERM return_term;
+ const EVP_MD *md = NULL;
+ ErlNifBinary ret_bin;
+#ifdef HAS_EVP_PKEY_CTX
+ size_t size;
+ EVP_PKEY *pkey = NULL;
+ EVP_MD_CTX *mctx = NULL;
+#endif
+
+ /*---------------------------------
+ Get common indata and validate it
+ */
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin))
+ {
+ return_term = EXCP_BADARG(env, "Bad key");
+ goto err;
+ }
+
+ if (!enif_inspect_iolist_as_binary(env, argv[3], &text))
+ {
+ return_term = EXCP_BADARG(env, "Bad text");
+ goto err;
+ }
+
+ if (!(macp = get_mac_type(argv[0], key_bin.size)))
+ {
+ if (!get_mac_type_no_key(argv[0]))
+ return_term = EXCP_BADARG(env, "Unknown mac algorithm");
+ else
+ return_term = EXCP_BADARG(env, "Bad key length");
+ goto err;
+ }
+
+ /*--------------------------------------------------
+ Algorithm dependent indata checking and computation.
+ If EVP_PKEY is available, only set the pkey variable
+ and do the computation after the switch statement.
+ If not available, do the low-level calls in the
+ corresponding case part
+ */
+ switch (macp->type) {
+
+ /********
+ * HMAC *
+ ********/
+ case HMAC_mac:
+ {
+ struct digest_type_t *digp;
+
+ if ((digp = get_digest_type(argv[1])) == NULL)
+ {
+ return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC");
+ goto err;
+ }
+ if (digp->md.p == NULL)
+ {
+ return_term = EXCP_NOTSUP(env, "Unsupported digest algorithm");
+ goto err;
+ }
+
+ md = digp->md.p;
+
+#ifdef HAS_EVP_PKEY_CTX
+# ifdef HAVE_PKEY_new_raw_private_key
+ /* Prefered for new applications according to EVP_PKEY_new_mac_key(3) */
+ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size);
+# else
+ /* Available in older versions */
+ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size);
+# endif
+
+#else
+ if (!hmac_low_level(env, md, key_bin, text, &ret_bin, &ret_bin_alloc, &return_term))
+ goto err;
+ else
+ goto success;
+#endif
+ }
+ break;
+
+
+ /********
+ * CMAC *
+ ********/
+#ifdef HAVE_CMAC
+ case CMAC_mac:
+ {
+ const struct cipher_type_t *cipherp;
+ if (!(cipherp = get_cipher_type(argv[1], key_bin.size)))
+ { /* Something went wrong. Find out what by retrying in another way. */
+ if (!get_cipher_type_no_key(argv[1]))
+ return_term = EXCP_BADARG(env, "Unknown cipher");
+ else
+ /* Cipher exists, so it must be the key size that is wrong */
+ return_term = EXCP_BADARG(env, "Bad key size");
+ goto err;
+ }
+
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ {
+ return_term = EXCP_NOTSUP(env, "Cipher algorithm not supported in FIPS");
+ goto err;
+ }
+
+ if (cipherp->cipher.p == NULL)
+ {
+ return_term = EXCP_NOTSUP(env, "Unsupported cipher algorithm");
+ goto err;
+ }
+
+# ifdef HAVE_EVP_PKEY_new_CMAC_key
+ pkey = EVP_PKEY_new_CMAC_key(/*engine*/ NULL, key_bin.data, key_bin.size, cipherp->cipher.p);
+# else
+ if (!cmac_low_level(env, key_bin, cipherp->cipher.p, text, &ret_bin, &ret_bin_alloc, &return_term))
+ goto err;
+ else
+ goto success;
+# endif
+ }
+ break;
+#endif /* HAVE_CMAC */
+
+
+ /************
+ * POLY1305 *
+ ************/
+#ifdef HAVE_POLY1305
+ case POLY1305_mac:
+ /* poly1305 implies that EVP_PKEY_new_raw_private_key exists */
+ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size);
+ break;
+#endif
+
+
+ /***************
+ * Unknown MAC *
+ ***************/
+ case NO_mac:
+ default:
+ /* We know that this mac is supported with some version(s) of cryptolib */
+ return_term = EXCP_NOTSUP(env, "Unsupported mac algorithm");
+ goto err;
+ }
+
+ /*-----------------------------------------
+ Common computations when we have EVP_PKEY
+ */
+#ifdef HAS_EVP_PKEY_CTX
+ if (!pkey)
+ {
+ return_term = EXCP_ERROR(env, "EVP_PKEY_key creation");
+ goto err;
+ }
+
+ if ((mctx = EVP_MD_CTX_new()) == NULL)
+ {
+ return_term = EXCP_ERROR(env, "EVP_MD_CTX_new");
+ goto err;
+ }
+
+ if (EVP_DigestSignInit(mctx, /*&pctx*/ NULL, md, /*engine*/ NULL, pkey) != 1)
+ {
+ return_term = EXCP_ERROR(env, "EVP_DigestSign");
+ goto err;
+ }
+
+# ifdef HAVE_DigestSign_as_single_op
+ if (EVP_DigestSign(mctx, NULL, &size, text.data, text.size) != 1)
+ {
+ return_term = EXCP_ERROR(env, "Can't get sign size");
+ goto err;
+ }
+# else
+ if (EVP_DigestSignUpdate(mctx, text.data, text.size) != 1)
+ {
+ return_term = EXCP_ERROR(env, "EVP_DigestSignUpdate");
+ goto err;
+ }
+
+ if (EVP_DigestSignFinal(mctx, NULL, &size) != 1)
+ {
+ return_term = EXCP_ERROR(env, "Can't get sign size");
+ goto err;
+ }
+# endif
+
+ if (!enif_alloc_binary(size, &ret_bin))
+ {
+ return_term = EXCP_ERROR(env, "Alloc binary");
+ goto err;
+ }
+ ret_bin_alloc = 1;
+
+# ifdef HAVE_DigestSign_as_single_op
+ if (EVP_DigestSign(mctx, ret_bin.data, &size, text.data, text.size) != 1)
+# else
+ if (EVP_DigestSignFinal(mctx, ret_bin.data, &size) != 1)
+# endif
+ {
+ return_term = EXCP_ERROR(env, "Signing");
+ goto err;
+ }
+
+ goto success; /* The label "success:" could be left without any "goto success"
+ in some combination of flags. This prevents a compiler warning
+ */
+#endif /* ifdef HAS_EVP_PKEY_CTX */
+
+
+ /****************************
+ Exit when we got a signature
+ *****************************/
+ success:
+ CONSUME_REDS(env, text);
+
+ return_term = enif_make_binary(env, &ret_bin);
+ ret_bin_alloc = 0;
+
+ err:
+
+#ifdef HAS_EVP_PKEY_CTX
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ if (mctx)
+ EVP_MD_CTX_free(mctx);
+#endif
+
+ if (ret_bin_alloc)
+ enif_release_binary(&ret_bin);
+
+ return return_term;
+}
+
+
+/*******************************************************************
+ *
+ * Mac ctx
+ *
+ ******************************************************************/
+
+int init_mac_ctx(ErlNifEnv *env);
+
+struct mac_context
+{
+ EVP_MD_CTX *ctx;
+};
+
+static ErlNifResourceType* mac_context_rtype;
+
+static void mac_context_dtor(ErlNifEnv* env, struct mac_context*);
+
+int init_mac_ctx(ErlNifEnv *env) {
+ mac_context_rtype = enif_open_resource_type(env, NULL, "mac_context",
+ (ErlNifResourceDtor*) mac_context_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+ if (mac_context_rtype == NULL)
+ goto err;
+
+ return 1;
+
+ err:
+ PRINTF_ERR0("CRYPTO: Could not open resource type 'mac_context'");
+ return 0;
+}
+
+
+static void mac_context_dtor(ErlNifEnv* env, struct mac_context *obj)
+{
+ if (obj == NULL)
+ return;
+
+ if (obj->ctx)
+ EVP_MD_CTX_free(obj->ctx);
+}
+
+/*******************************************************************
+ *
+ * mac_init, mac_update, mac_final nifs
+ *
+ ******************************************************************/
+
+ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (MacType, SubType, Key) */
+#ifdef HAS_EVP_PKEY_CTX
+ struct mac_context *obj = NULL;
+ struct mac_type_t *macp;
+ ErlNifBinary key_bin;
+ ERL_NIF_TERM return_term;
+ const EVP_MD *md = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ /*---------------------------------
+ Get common indata and validate it
+ */
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin))
+ {
+ return_term = EXCP_BADARG(env, "Bad key");
+ goto err;
+ }
+
+ if (!(macp = get_mac_type(argv[0], key_bin.size)))
+ {
+ if (!get_mac_type_no_key(argv[0]))
+ return_term = EXCP_BADARG(env, "Unknown mac algorithm");
+ else
+ return_term = EXCP_BADARG(env, "Bad key length");
+ goto err;
+ }
+
+ /*--------------------------------------------------
+ Algorithm dependent indata checking and computation.
+ If EVP_PKEY is available, only set the pkey variable
+ and do the computation after the switch statement.
+ If not available, do the low-level calls in the
+ corresponding case part
+ */
+ switch (macp->type) {
+
+ /********
+ * HMAC *
+ ********/
+ case HMAC_mac:
+ {
+ struct digest_type_t *digp;
+
+ if ((digp = get_digest_type(argv[1])) == NULL)
+ {
+ return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC");
+ goto err;
+ }
+ if (digp->md.p == NULL)
+ {
+ return_term = EXCP_NOTSUP(env, "Unsupported digest algorithm");
+ goto err;
+ }
+
+ md = digp->md.p;
+
+# ifdef HAVE_PKEY_new_raw_private_key
+ /* Prefered for new applications according to EVP_PKEY_new_mac_key(3) */
+ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size);
+# else
+ /* Available in older versions */
+ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size);
+# endif
+ }
+ break;
+
+
+ /********
+ * CMAC *
+ ********/
+#if defined(HAVE_CMAC) && defined(HAVE_EVP_PKEY_new_CMAC_key)
+ case CMAC_mac:
+ {
+ const struct cipher_type_t *cipherp;
+ if (!(cipherp = get_cipher_type(argv[1], key_bin.size)))
+ { /* Something went wrong. Find out what by retrying in another way. */
+ if (!get_cipher_type_no_key(argv[1]))
+ return_term = EXCP_BADARG(env, "Unknown cipher");
+ else
+ /* Cipher exists, so it must be the key size that is wrong */
+ return_term = EXCP_BADARG(env, "Bad key size");
+ goto err;
+ }
+
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ {
+ return_term = EXCP_NOTSUP(env, "Cipher algorithm not supported in FIPS");
+ goto err;
+ }
+
+ if (cipherp->cipher.p == NULL)
+ {
+ return_term = EXCP_NOTSUP(env, "Unsupported cipher algorithm");
+ goto err;
+ }
+
+ pkey = EVP_PKEY_new_CMAC_key(/*engine*/ NULL, key_bin.data, key_bin.size, cipherp->cipher.p);
+ }
+ break;
+#endif /* HAVE_CMAC && HAVE_EVP_PKEY_new_CMAC_key */
+
+
+ /************
+ * POLY1305 *
+ ************/
+#ifdef HAVE_POLY1305
+ case POLY1305_mac:
+ /* poly1305 implies that EVP_PKEY_new_raw_private_key exists */
+ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size);
+ break;
+#endif
+
+
+ /***************
+ * Unknown MAC *
+ ***************/
+ case NO_mac:
+ default:
+ /* We know that this mac is supported with some version(s) of cryptolib */
+ return_term = EXCP_NOTSUP(env, "Unsupported mac algorithm");
+ goto err;
+ }
+
+ /*-----------------------------------------
+ Common computations
+ */
+ if (!pkey)
+ {
+ return_term = EXCP_ERROR(env, "EVP_PKEY_key creation");
+ goto err;
+ }
+
+ if ((obj = enif_alloc_resource(mac_context_rtype, sizeof(struct mac_context))) == NULL)
+ {
+ return_term = EXCP_ERROR(env, "Can't allocate mac_context_rtype");
+ goto err;
+ }
+
+ if ((obj->ctx = EVP_MD_CTX_new()) == NULL)
+ {
+ return_term = EXCP_ERROR(env, "EVP_MD_CTX_new");
+ goto err;
+ }
+
+ if (EVP_DigestSignInit(obj->ctx, /*&pctx*/ NULL, md, /*engine*/ NULL, pkey) != 1)
+ {
+ return_term = EXCP_ERROR(env, "EVP_DigestSign");
+ goto err;
+ }
+
+ return_term = enif_make_resource(env, obj);
+
+ err:
+
+ if (obj)
+ enif_release_resource(obj);
+
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ return return_term;
+
+#else
+ if (argv[0] != atom_hmac)
+ return EXCP_NOTSUP(env, "Unsupported mac algorithm");
+
+ return hmac_init_nif(env, argc, argv);
+#endif
+}
+
+
+
+ERL_NIF_TERM mac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Ref, Text) */
+ ErlNifBinary text;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &text))
+ return EXCP_BADARG(env, "Bad text");
+
+ if (text.size > INT_MAX)
+ return EXCP_BADARG(env, "Too long text");
+
+ /* Run long jobs on a dirty scheduler to not block the current emulator thread */
+ if (text.size > MAX_BYTES_TO_NIF) {
+ return enif_schedule_nif(env, "mac_update",
+ ERL_NIF_DIRTY_JOB_CPU_BOUND,
+ mac_update, argc, argv);
+ }
+
+ return mac_update(env, argc, argv);
+}
+
+
+ERL_NIF_TERM mac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Ref, Text) */
+#ifdef HAS_EVP_PKEY_CTX
+ struct mac_context *obj = NULL;
+ ErlNifBinary text;
+
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj))
+ return EXCP_BADARG(env, "Bad ref");
+
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &text))
+ return EXCP_BADARG(env, "Bad text");
+
+ if (EVP_DigestSignUpdate(obj->ctx, text.data, text.size) != 1)
+ return EXCP_ERROR(env, "EVP_DigestSignUpdate");
+
+ CONSUME_REDS(env, text);
+ return argv[0];
+
+#else
+ return hmac_update_nif(env, argc, argv);
+#endif
+}
+
+
+
+ERL_NIF_TERM mac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Ref) */
+#ifdef HAS_EVP_PKEY_CTX
+ struct mac_context *obj;
+ size_t size;
+ ErlNifBinary ret_bin;
+
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj))
+ return EXCP_BADARG(env, "Bad ref");
+
+ if (EVP_DigestSignFinal(obj->ctx, NULL, &size) != 1)
+ return EXCP_ERROR(env, "Can't get sign size");
+
+ if (!enif_alloc_binary(size, &ret_bin))
+ return EXCP_ERROR(env, "Alloc binary");
+
+ if (EVP_DigestSignFinal(obj->ctx, ret_bin.data, &size) != 1)
+ {
+ enif_release_binary(&ret_bin);
+ return EXCP_ERROR(env, "Signing");
+ }
+
+ return enif_make_binary(env, &ret_bin);
+
+#else
+ return hmac_final_nif(env, argc, argv);
+#endif
+}
+
diff --git a/lib/crypto/c_src/poly1305.h b/lib/crypto/c_src/mac.h
index 4bf45e6218..053a331324 100644
--- a/lib/crypto/c_src/poly1305.h
+++ b/lib/crypto/c_src/mac.h
@@ -18,11 +18,21 @@
* %CopyrightEnd%
*/
-#ifndef E_POLY1305_H__
-#define E_POLY1305_H__ 1
+#ifndef E_MAC_H__
+#define E_MAC_H__ 1
#include "common.h"
-ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+int init_mac_ctx(ErlNifEnv *env);
-#endif /* E_POLY1305_H__ */
+void init_mac_types(ErlNifEnv* env);
+
+ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env);
+
+ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM mac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM mac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_MAC_H__ */
diff --git a/lib/crypto/c_src/openssl_config.h b/lib/crypto/c_src/openssl_config.h
index 339eb5b8f4..32a0830717 100644
--- a/lib/crypto/c_src/openssl_config.h
+++ b/lib/crypto/c_src/openssl_config.h
@@ -110,6 +110,12 @@
# define HAS_EVP_PKEY_CTX
# define HAVE_EVP_CIPHER_CTX_COPY
# endif
+
+# if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,1)
+# define HAVE_PKEY_new_raw_private_key
+# define HAVE_EVP_PKEY_new_CMAC_key
+# define HAVE_DigestSign_as_single_op
+# endif
#endif
diff --git a/lib/crypto/c_src/pkey.c b/lib/crypto/c_src/pkey.c
index a1e2677b34..d53d91c25b 100644
--- a/lib/crypto/c_src/pkey.c
+++ b/lib/crypto/c_src/pkey.c
@@ -59,8 +59,9 @@ static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_T
EVP_PKEY **pkey);
static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options,
PKeyCryptOptions *opt);
+#ifdef HAVE_RSA_SSLV23_PADDING
static size_t size_of_RSA(EVP_PKEY *pkey);
-
+#endif
static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM type,
const EVP_MD **md)
@@ -1031,6 +1032,7 @@ static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NI
return PKEY_BADARG;
}
+#ifdef HAVE_RSA_SSLV23_PADDING
static size_t size_of_RSA(EVP_PKEY *pkey) {
int ret = 0;
RSA *rsa = NULL;
@@ -1045,6 +1047,7 @@ static size_t size_of_RSA(EVP_PKEY *pkey) {
return (ret < 0) ? 0 : (size_t)ret;
}
+#endif
ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{/* (Algorithm, Data, PublKey=[E,N]|[E,N,D]|[E,N,D,P1,P2,E1,E2,C], Options, IsPrivate, IsEncrypt) */
diff --git a/lib/crypto/c_src/poly1305.c b/lib/crypto/c_src/poly1305.c
deleted file mode 100644
index 76579c0a29..0000000000
--- a/lib/crypto/c_src/poly1305.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2010-2018. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- */
-
-#include "poly1305.h"
-
-/* For OpenSSL >= 1.1.1 the hmac_nif and cmac_nif could be integrated into poly1305 (with 'type' as parameter) */
-ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key, Text) */
-#ifdef HAVE_POLY1305
- ErlNifBinary key_bin, text, ret_bin;
- ERL_NIF_TERM ret;
- EVP_PKEY *key = NULL;
- EVP_MD_CTX *mctx = NULL;
- EVP_PKEY_CTX *pctx = NULL;
- const EVP_MD *md = NULL;
- size_t size;
- int ret_bin_alloc = 0;
-
- ASSERT(argc == 2);
-
- if (!enif_inspect_binary(env, argv[0], &key_bin))
- goto bad_arg;
- if (key_bin.size != 32)
- goto bad_arg;
- if (!enif_inspect_binary(env, argv[1], &text))
- goto bad_arg;
-
- if ((key = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size)) == NULL)
- goto err;
-
- if ((mctx = EVP_MD_CTX_new()) == NULL)
- goto err;
- if (EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, key) != 1)
- goto err;
- if (EVP_DigestSignUpdate(mctx, text.data, text.size) != 1)
- goto err;
-
- if (EVP_DigestSignFinal(mctx, NULL, &size) != 1)
- goto err;
- if (!enif_alloc_binary(size, &ret_bin))
- goto err;
- ret_bin_alloc = 1;
- if (EVP_DigestSignFinal(mctx, ret_bin.data, &size) != 1)
- goto err;
-
- if (size != ret_bin.size) {
- if (!enif_realloc_binary(&ret_bin, size))
- goto err;
- }
-
- ret = enif_make_binary(env, &ret_bin);
- ret_bin_alloc = 0;
- goto done;
-
- bad_arg:
- return enif_make_badarg(env);
-
- err:
- if (ret_bin_alloc)
- enif_release_binary(&ret_bin);
- ret = atom_error;
-
- done:
- if (mctx)
- EVP_MD_CTX_free(mctx);
- if (key)
- EVP_PKEY_free(key);
- return ret;
-
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
diff --git a/lib/crypto/doc/src/algorithm_details.xml b/lib/crypto/doc/src/algorithm_details.xml
index 854bfbb4b1..71014764c8 100644
--- a/lib/crypto/doc/src/algorithm_details.xml
+++ b/lib/crypto/doc/src/algorithm_details.xml
@@ -37,122 +37,163 @@
<section>
<title>Ciphers</title>
+ <p>A <seealso marker="crypto#type-cipher">cipher</seealso> in the
+ <seealso marker="crypto:new_api#the-new-api">new api</seealso>
+ is categorized as either
+ <seealso marker="crypto#type-cipher_no_iv">cipher_no_iv()</seealso>,
+ <seealso marker="crypto#type-cipher_iv">cipher_iv()</seealso> or
+ <seealso marker="crypto#type-cipher_aead">cipher_aead()</seealso>.
+ The letters IV are short for <i>Initialization Vector</i> and
+ AEAD is an abreviation of <i>Authenticated Encryption with Associated Data</i>.
+ </p>
+ <p>Due to irregular naming conventions, some cipher names in the old api are
+ substitued by new names in the new api. For a list of retired names, see
+ <seealso marker="crypto:new_api#retired-cipher-names">Retired cipher names</seealso>.
+ </p>
+ <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(ciphers)</seealso>.
+ </p>
+
<section>
- <title>Block Ciphers</title>
- <p>To be used in
- <seealso marker="crypto#block_encrypt-3">block_encrypt/3</seealso>,
- <seealso marker="crypto#block_encrypt-4">block_encrypt/4</seealso>,
- <seealso marker="crypto#block_decrypt-3">block_decrypt/3</seealso> and
- <seealso marker="crypto#block_decrypt-4">block_decrypt/4</seealso>.
- </p>
- <p>Available in all OpenSSL compatible with Erlang CRYPTO if not disabled by configuration.
+ <title>Ciphers without an IV - cipher_no_iv()</title>
+ <p>To be used with:
</p>
- <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
- list with the <c>cipher</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ <list>
+ <item><seealso marker="crypto#crypto_one_time/4">crypto_one_time/4</seealso></item>
+ <item><seealso marker="crypto#crypto_init/3">crypto_init/3</seealso></item>
+ </list>
+ <p>The ciphers are:
</p>
<table>
- <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Block size</strong><br/><strong>[bytes]</strong></cell></row>
- <row><cell><c>aes_cbc</c></cell> <cell>16, 24, 32</cell><cell>16</cell><cell>16</cell></row>
- <row><cell><c>aes_cbc128</c></cell><cell>16</cell><cell>16</cell><cell>16</cell></row>
- <row><cell><c>aes_cbc256</c></cell><cell>32</cell><cell>16</cell><cell>16</cell></row>
-
- <row><cell><c>aes_cfb8</c></cell> <cell>16, 24, 32</cell><cell>16</cell><cell>any</cell></row>
-
- <row><cell><c>aes_ecb</c></cell><cell>16, 24, 32</cell><cell> </cell><cell>16</cell></row>
-
- <row><cell><c>aes_ige256</c></cell><cell>16</cell><cell>32</cell><cell>16</cell></row>
- <row><cell><c>blowfish_cbc</c></cell> <cell>4-56</cell> <cell>8</cell> <cell>8</cell></row>
- <row><cell><c>blowfish_cfb64</c></cell> <cell>&#8805;1</cell> <cell>8</cell> <cell>any</cell></row>
- <row><cell><c>blowfish_ecb</c></cell><cell>&#8805;1</cell><cell> </cell><cell>8</cell></row>
- <row><cell><c>blowfish_ofb64</c></cell><cell>&#8805;1</cell><cell>8</cell><cell>any</cell></row>
-
- <row><cell><c>des3_cbc</c><br/><i>(=DES EDE3 CBC)</i></cell><cell>[8,8,8]</cell><cell>8</cell><cell>8</cell></row>
- <row><cell><c>des3_cfb</c><br/><i>(=DES EDE3 CFB)</i></cell><cell>[8,8,8]</cell><cell>8</cell><cell>any</cell></row>
-
- <row><cell><c>des_cbc</c></cell><cell>8</cell><cell>8</cell> <cell>8</cell></row>
- <row><cell><c>des_cfb</c></cell><cell>8</cell><cell>8</cell><cell>any</cell></row>
- <row><cell><c>des_ecb</c></cell><cell>8</cell><cell> </cell><cell>8</cell></row>
- <row><cell><c>des_ede3</c><br/><i>(=DES EDE3 CBC)</i></cell><cell>[8,8,8]</cell><cell>8</cell><cell>8</cell></row>
- <row><cell><c>rc2_cbc</c></cell><cell>&#8805;1</cell><cell>8</cell><cell>8</cell></row>
- <tcaption>Block cipher key lengths</tcaption>
+ <row>
+ <cell><strong>Cipher and Mode</strong></cell>
+ <cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>Block size</strong><br/><strong>[bytes]</strong></cell>
+ </row>
+ <row><cell><c>aes_128_ecb</c></cell> <cell>16</cell> <cell>16</cell></row>
+ <row><cell><c>aes_192_ecb</c></cell> <cell>24</cell> <cell>16</cell></row>
+ <row><cell><c>aes_256_ecb</c></cell> <cell>32</cell> <cell>16</cell></row>
+ <row><cell><c>blowfish_ecb</c></cell> <cell>16</cell> <cell>&nbsp;8</cell></row>
+ <row><cell><c>des_ecb</c></cell> <cell>&nbsp;8</cell> <cell>&nbsp;8</cell></row>
+ <row><cell><c>rc4</c></cell> <cell>16</cell> <cell>&nbsp;1</cell></row>
+ <tcaption>Ciphers without IV</tcaption>
</table>
</section>
<section>
- <title>AEAD Ciphers</title>
- <p>To be used in <seealso marker="crypto#block_encrypt-4">block_encrypt/4</seealso> and
- <seealso marker="crypto#block_decrypt-4">block_decrypt/4</seealso>.
+ <title>Ciphers with an IV - cipher_iv()</title>
+ <p>To be used with:
</p>
- <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
- list with the <c>cipher</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ <list>
+ <item><seealso marker="crypto#crypto_one_time/5">crypto_one_time/5</seealso></item>
+ <item><seealso marker="crypto#crypto_init/4">crypto_init/4</seealso></item>
+ <item><seealso marker="crypto#crypto_dyn_iv_init/3">crypto_dyn_iv_init/3</seealso></item>
+ </list>
+ <p>The ciphers are:
</p>
<table>
- <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell><cell><strong>AAD length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Tag length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Block size</strong><br/><strong>[bytes]</strong></cell><cell><strong>Supported with</strong><br/><strong>OpenSSL versions</strong></cell></row>
- <row><cell><c>aes_ccm</c></cell> <cell>16,24,32</cell> <cell>7-13</cell> <cell>any</cell> <cell>even 4-16<br/>default: 12</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
- <row><cell><c>aes_gcm</c></cell> <cell>16,24,32</cell> <cell>&#8805;1</cell> <cell>any</cell> <cell>1-16<br/>default: 16</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
- <row><cell><c>chacha20_poly1305</c></cell><cell>32</cell> <cell>1-16</cell> <cell>any</cell> <cell>16</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
- <tcaption>AEAD cipher key lengths</tcaption>
+ <row>
+ <cell><strong>Cipher and Mode</strong></cell>
+ <cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>Block size</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>Limited to</strong><br/><strong>OpenSSL versions</strong></cell>
+ </row>
+ <row><cell><c>aes_128_cbc</c></cell> <cell>16</cell> <cell>16</cell> <cell>16</cell> <cell></cell></row>
+ <row><cell><c>aes_192_cbc</c></cell> <cell>24</cell> <cell>16</cell> <cell>16</cell> <cell></cell></row>
+ <row><cell><c>aes_256_cbc</c></cell> <cell>32</cell> <cell>16</cell> <cell>16</cell> <cell></cell></row>
+ <row><cell><c>aes_128_cfb8</c></cell> <cell>16</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>aes_192_cfb8</c></cell> <cell>24</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>aes_256_cfb8</c></cell> <cell>32</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>aes_128_cfb128</c></cell><cell>16</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>aes_192_cfb128</c></cell><cell>24</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>aes_256_cfb128</c></cell><cell>32</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>aes_128_ctr</c></cell> <cell>16</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>aes_192_ctr</c></cell> <cell>24</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>aes_256_ctr</c></cell> <cell>32</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>aes_ige256</c></cell> <cell>16</cell> <cell>32</cell> <cell>16</cell> <cell></cell></row>
+ <row><cell><c>blowfish_cbc</c></cell> <cell>16</cell> <cell>&nbsp;8</cell> <cell>&nbsp;8</cell> <cell></cell></row>
+ <row><cell><c>blowfish_cfb64</c></cell><cell>16</cell> <cell>&nbsp;8</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>blowfish_ofb64</c></cell><cell>16</cell> <cell>&nbsp;8</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>chacha20</c></cell> <cell>32</cell> <cell>16</cell> <cell>&nbsp;1</cell> <cell>&#8805;1.1.0d</cell></row>
+ <row><cell><c>des_cbc</c></cell> <cell>&nbsp;8</cell> <cell>&nbsp;8</cell> <cell>&nbsp;8</cell> <cell></cell></row>
+ <row><cell><c>des_ede3_cbc</c></cell> <cell>24</cell> <cell>&nbsp;8</cell> <cell>&nbsp;8</cell> <cell></cell></row>
+ <row><cell><c>des_cfb</c></cell> <cell>&nbsp;8</cell> <cell>&nbsp;8</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>des_ede3_cfb</c></cell> <cell>24</cell> <cell>&nbsp;8</cell> <cell>&nbsp;1</cell> <cell></cell></row>
+ <row><cell><c>rc2_cbc</c></cell> <cell>16</cell> <cell>&nbsp;8</cell> <cell>&nbsp;8</cell> <cell></cell></row>
+ <tcaption>Ciphers with IV</tcaption>
</table>
</section>
<section>
- <title>Stream Ciphers</title>
- <p>To be used in <seealso marker="crypto#stream_init-2">stream_init/2</seealso> and
- <seealso marker="crypto#stream_init/3">stream_init/3</seealso>.
+ <title>Ciphers with AEAD - cipher_aead()</title>
+ <p>To be used with:
</p>
- <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
- list with the <c>cipher</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ <list>
+ <item><seealso marker="crypto#crypto_one_time_aead/6">crypto_one_time_aead/6</seealso></item>
+ <item><seealso marker="crypto#crypto_one_time_aead/7">crypto_one_time_aead/7</seealso></item>
+ </list>
+ <p>The ciphers are:
</p>
<table>
- <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Supported with</strong><br/><strong>OpenSSL versions</strong></cell></row>
- <row><cell><c>aes_ctr</c></cell><cell>16, 24, 32</cell><cell>16</cell><cell>&#8805;1.0.1</cell></row>
- <row><cell><c>rc4</c></cell><cell>&#8805;1</cell><cell> </cell> <cell>all</cell></row>
- <tcaption>Stream cipher key lengths</tcaption>
+ <row>
+ <cell><strong>Cipher and Mode</strong></cell>
+ <cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>AAD length</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>Tag length</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>Block size</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>Limited to</strong><br/><strong>OpenSSL versions</strong></cell>
+ </row>
+ <row><cell><c>aes_128_ccm</c></cell> <cell>16</cell> <cell>7-13</cell> <cell>any</cell> <cell>even 4-16<br/>default: 12</cell> <cell>any</cell><cell>&#8805;1.0.1</cell></row>
+ <row><cell><c>aes_192_ccm</c></cell> <cell>24</cell> <cell>7-13</cell> <cell>any</cell> <cell>even 4-16<br/>default: 12</cell> <cell>any</cell><cell>&#8805;1.0.1</cell></row>
+ <row><cell><c>aes_256_ccm</c></cell> <cell>32</cell> <cell>7-13</cell> <cell>any</cell> <cell>even 4-16<br/>default: 12</cell> <cell>any</cell><cell>&#8805;1.0.1</cell></row>
+
+ <row><cell><c>aes_128_gcm</c></cell> <cell>16</cell> <cell>&#8805;1</cell> <cell>any</cell> <cell>1-16<br/>default: 16</cell> <cell>any</cell><cell>&#8805;1.0.1</cell></row>
+ <row><cell><c>aes_192_gcm</c></cell> <cell>24</cell> <cell>&#8805;1</cell> <cell>any</cell> <cell>1-16<br/>default: 16</cell> <cell>any</cell><cell>&#8805;1.0.1</cell></row>
+ <row><cell><c>aes_256_gcm</c></cell> <cell>32</cell> <cell>&#8805;1</cell> <cell>any</cell> <cell>1-16<br/>default: 16</cell> <cell>any</cell><cell>&#8805;1.0.1</cell></row>
+
+ <row><cell><c>chacha20_poly1305</c></cell><cell>32</cell> <cell>1-16</cell> <cell>any</cell> <cell>16</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
+ <tcaption>AEAD ciphers</tcaption>
</table>
</section>
</section>
+
<section>
<title>Message Authentication Codes (MACs)</title>
+ <p>To be used in <seealso marker="crypto#mac-4">mac/4</seealso> and
+ <seealso marker="crypto:new_api#macs--message-authentication-codes-">related functions</seealso>.
+ </p>
<section>
<title>CMAC</title>
- <p>To be used in <seealso marker="crypto#cmac-3">cmac/3</seealso> and
- <seealso marker="crypto#cmac-3">cmac/4</seealso>.
- </p>
<p>CMAC with the following ciphers are available with OpenSSL 1.0.1 or later if not disabled by configuration.
</p>
<p>To dynamically check availability, check that the name <c>cmac</c> is present in the
- list with the <c>macs</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(macs)</seealso>.
Also check that the name in the <i>Cipher and Mode</i> column is present in the
- list with the <c>cipher</c> tag in the return value.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(ciphers)</seealso>.
</p>
<table>
- <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Max Mac Length</strong><br/><strong>[bytes]</strong></cell></row>
- <row><cell><c>aes_cbc</c></cell> <cell>16, 24, 32</cell><cell>16</cell></row>
- <row><cell><c>aes_cbc128</c></cell><cell>16</cell><cell>16</cell></row>
- <row><cell><c>aes_cbc256</c></cell><cell>32</cell><cell>16</cell></row>
-
- <row><cell><c>aes_cfb8</c></cell> <cell>16</cell><cell>1</cell></row>
-
- <row><cell><c>blowfish_cbc</c></cell> <cell>4-56</cell> <cell>8</cell></row>
- <row><cell><c>blowfish_cfb64</c></cell> <cell>&#8805;1</cell> <cell>1</cell></row>
- <row><cell><c>blowfish_ecb</c></cell><cell>&#8805;1</cell> <cell>8</cell></row>
- <row><cell><c>blowfish_ofb64</c></cell><cell>&#8805;1</cell> <cell>1</cell></row>
-
- <row><cell><c>des3_cbc</c><br/><i>(=DES EDE3 CBC)</i></cell><cell>[8,8,8]</cell><cell>8</cell></row>
- <row><cell><c>des3_cfb</c><br/><i>(=DES EDE3 CFB)</i></cell><cell>[8,8,8]</cell><cell>1</cell></row>
-
- <row><cell><c>des_cbc</c></cell><cell>8</cell><cell>8</cell></row>
-
- <row><cell><c>des_cfb</c></cell><cell>8</cell><cell>1</cell></row>
- <row><cell><c>des_ecb</c></cell><cell>8</cell><cell>1</cell></row>
- <row><cell><c>rc2_cbc</c></cell><cell>&#8805;1</cell><cell>8</cell></row>
+ <row>
+ <cell><strong>Cipher and Mode</strong></cell>
+ <cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell>
+ <cell><strong>Max Mac Length</strong><br/><strong>(= default length)</strong><br/><strong>[bytes]</strong></cell>
+ </row>
+ <row><cell><c>aes_128_cbc</c></cell> <cell>16</cell> <cell>16</cell></row>
+ <row><cell><c>aes_192_cbc</c></cell> <cell>24</cell> <cell>16</cell></row>
+ <row><cell><c>aes_256_cbc</c></cell> <cell>32</cell> <cell>16</cell></row>
+ <row><cell><c>aes_128_ecb</c></cell> <cell>16</cell> <cell>16</cell></row>
+ <row><cell><c>aes_192_ecb</c></cell> <cell>24</cell> <cell>16</cell></row>
+ <row><cell><c>aes_256_ecb</c></cell> <cell>32</cell> <cell>16</cell></row>
+ <row><cell><c>blowfish_cbc</c></cell> <cell>16</cell> <cell>&nbsp;8</cell></row>
+ <row><cell><c>blowfish_ecb</c></cell> <cell>16</cell> <cell>&nbsp;8</cell></row>
+ <row><cell><c>des_cbc</c></cell> <cell>&nbsp;8</cell> <cell>&nbsp;8</cell></row>
+ <row><cell><c>des_ecb</c></cell> <cell>&nbsp;8</cell> <cell>&nbsp;8</cell></row>
+ <row><cell><c>des_ede3_cbc</c></cell> <cell>24</cell> <cell>&nbsp;8</cell></row>
+ <row><cell><c>rc2_cbc</c></cell> <cell>16</cell> <cell>&nbsp;8</cell></row>
<tcaption>CMAC cipher key lengths</tcaption>
</table>
</section>
@@ -162,9 +203,34 @@
<p>Available in all OpenSSL compatible with Erlang CRYPTO if not disabled by configuration.
</p>
<p>To dynamically check availability, check that the name <c>hmac</c> is present in the
- list with the <c>macs</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(macs)</seealso> and
+ that the hash name is present in the
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(hashs)</seealso>.
</p>
+
+ <table>
+ <row>
+ <cell><strong>Hash</strong></cell>
+ <cell><strong>Max Mac Length</strong><br/><strong>(= default length)</strong><br/><strong>[bytes]</strong></cell>
+ </row>
+ <row><cell><c>sha</c></cell> <cell>20</cell></row>
+ <row><cell><c>sha224</c></cell> <cell>28</cell></row>
+ <row><cell><c>sha256</c></cell> <cell>32</cell></row>
+ <row><cell><c>sha384</c></cell> <cell>48</cell></row>
+ <row><cell><c>sha512</c></cell> <cell>64</cell></row>
+ <row><cell><c>sha3_224</c></cell> <cell>28</cell></row>
+ <row><cell><c>sha3_256</c></cell> <cell>32</cell></row>
+ <row><cell><c>sha3_384</c></cell> <cell>48</cell></row>
+ <row><cell><c>sha3_512</c></cell> <cell>64</cell></row>
+ <row><cell><c>blake2b</c></cell> <cell>64</cell></row>
+ <row><cell><c>blake2s</c></cell> <cell>32</cell></row>
+ <row><cell><c>md4</c></cell> <cell>16</cell></row>
+ <row><cell><c>md5</c></cell> <cell>16</cell></row>
+ <row><cell><c>ripemd160</c></cell> <cell>20</cell></row>
+ <tcaption>HMAC output sizes</tcaption>
+ </table>
+
+
</section>
<section>
@@ -172,8 +238,9 @@
<p>POLY1305 is available with OpenSSL 1.1.1 or later if not disabled by configuration.
</p>
<p>To dynamically check availability, check that the name <c>poly1305</c> is present in the
- list with the <c>macs</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(macs)</seealso>.
+ </p>
+ <p>The poly1305 mac wants an 32 bytes key and produces a 16 byte MAC by default.
</p>
</section>
@@ -183,22 +250,20 @@
<title>Hash</title>
<p>To dynamically check availability, check that the wanted name in the <i>Names</i> column is present in the
- list with the <c>hashs</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(hashs)</seealso>.
</p>
-
<table>
<row><cell><strong>Type</strong></cell>
<cell><strong>Names</strong></cell>
- <cell><strong>Supported with</strong><br/><strong>OpenSSL versions</strong></cell>
+ <cell><strong>Limitated to</strong><br/><strong>OpenSSL versions</strong></cell>
</row>
- <row><cell>SHA1</cell><cell>sha</cell><cell>all</cell></row>
- <row><cell>SHA2</cell><cell>sha224, sha256, sha384, sha512</cell><cell>all</cell></row>
+ <row><cell>SHA1</cell><cell>sha</cell><cell></cell></row>
+ <row><cell>SHA2</cell><cell>sha224, sha256, sha384, sha512</cell><cell></cell></row>
<row><cell>SHA3</cell><cell>sha3_224, sha3_256, sha3_384, sha3_512</cell><cell>&#8805;1.1.1</cell></row>
- <row><cell>MD4</cell><cell>md4</cell><cell>all</cell></row>
- <row><cell>MD5</cell><cell>md5</cell><cell>all</cell></row>
- <row><cell>RIPEMD</cell><cell>ripemd160</cell><cell>all</cell></row>
+ <row><cell>MD4</cell><cell>md4</cell><cell></cell></row>
+ <row><cell>MD5</cell><cell>md5</cell><cell></cell></row>
+ <row><cell>RIPEMD</cell><cell>ripemd160</cell><cell></cell></row>
<tcaption></tcaption>
</table>
</section>
@@ -210,8 +275,7 @@
<title>RSA</title>
<p>RSA is available with all OpenSSL versions compatible with Erlang CRYPTO if not disabled by configuration.
To dynamically check availability, check that the atom <c>rsa</c> is present in the
- list with the <c>public_keys</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(public_keys)</seealso>.
</p>
<warning>
<!-- In RefMan rsa_opt(), rsa_sign_verify_opt() and User's man RSA -->
@@ -283,8 +347,7 @@
<title>DSS</title>
<p>DSS is available with OpenSSL versions compatible with Erlang CRYPTO if not disabled by configuration.
To dynamically check availability, check that the atom <c>dss</c> is present in the
- list with the <c>public_keys</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(public_keys)</seealso>.
</p>
</section>
@@ -292,13 +355,11 @@
<title>ECDSA</title>
<p>ECDSA is available with OpenSSL 0.9.8o or later if not disabled by configuration.
To dynamically check availability, check that the atom <c>ecdsa</c> is present in the
- list with the <c>public_keys</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
- If the atom <c>ec_gf2m</c> characteristic two field curves are available.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(public_keys)</seealso>.
+ If the atom <c>ec_gf2m</c> also is present, the characteristic two field curves are available.
</p>
- <p>The actual supported named curves could be checked by examining the list with the
- <c>curves</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ <p>The actual supported named curves could be checked by examining the
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(curves)</seealso>.
</p>
</section>
@@ -306,13 +367,11 @@
<title>EdDSA</title>
<p>EdDSA is available with OpenSSL 1.1.1 or later if not disabled by configuration.
To dynamically check availability, check that the atom <c>eddsa</c> is present in the
- list with the <c>public_keys</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(public_keys)</seealso>.
</p>
<p>Support for the curves ed25519 and ed448 is implemented.
The actual supported named curves could be checked by examining the list with the
- <c>curves</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(curves)</seealso>.
</p>
</section>
@@ -321,8 +380,7 @@
<p>Diffie-Hellman computations are available with OpenSSL versions compatible with Erlang CRYPTO
if not disabled by configuration.
To dynamically check availability, check that the atom <c>dh</c> is present in the
- list with the <c>public_keys</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(public_keys)</seealso>.
</p>
</section>
@@ -330,17 +388,15 @@
<title>Elliptic Curve Diffie-Hellman</title>
<p>Elliptic Curve Diffie-Hellman is available with OpenSSL 0.9.8o or later if not disabled by configuration.
To dynamically check availability, check that the atom <c>ecdh</c> is present in the
- list with the <c>public_keys</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(public_keys)</seealso>.
</p>
<p>The Edward curves <c>x25519</c> and <c>x448</c> are supported with OpenSSL 1.1.1 or later
if not disabled by configuration.
</p>
- <p>The actual supported named curves could be checked by examining the list with the
- <c>curves</c> tag in the return value of
- <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ <p>The actual supported named curves could be checked by examining the
+ list returned by <seealso marker="crypto#supports-1">crypto:supports(curves)</seealso>.
</p>
</section>
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index d1d1252f29..8988a18482 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -302,6 +302,12 @@
</datatype>
<datatype>
+ <name name="cmac_cipher_algorithm"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
<name name="rsa_digest_type"/>
<desc>
</desc>
@@ -324,6 +330,11 @@
<name name="sha2"/>
<name name="sha3"/>
<name name="blake2"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
<name name="compatibility_only_hash"/>
<desc>
<p>The <c>compatibility_only_hash()</c> algorithms are recommended only for compatibility with existing applications.</p>
@@ -575,10 +586,11 @@
<datatype_title>Internal data types</datatype_title>
<datatype>
- <name name="stream_state"/>
- <name name="hmac_state"/>
- <name name="hash_state"/>
<name name="crypto_state"/>
+ <name name="hash_state"/>
+ <name name="hmac_state"/>
+ <name name="mac_state"/>
+ <name name="stream_state"/>
<desc>
<p>Contexts with an internal state that should not be manipulated but passed between function calls.
</p>
@@ -783,6 +795,187 @@
</desc>
</func>
+ <func>
+ <name name="mac" arity="3" since="OTP @OTP-13872@"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Short for <seealso marker="#mac-4">mac(Type, undefined, Key, Data)</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="mac" arity="4" since="OTP @OTP-13872@"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Computes a MAC (Message Authentication Code) of type <c>Type</c> from <c>Data</c>.
+ </p>
+
+ <p><c>SubType</c> depends on the MAC <c>Type</c>:
+ </p>
+ <list>
+ <item>For <c>hmac</c> it is a hash algorithm, see
+ <seealso marker="algorithm_details#hmac">Algorithm Details</seealso> in the User's Guide.
+ </item>
+ <item>For <c>cmac</c> it is a cipher suitable for cmac, see
+ <seealso marker="algorithm_details#cmac">Algorithm Details</seealso> in the User's Guide.
+ </item>
+ <item>For <c>poly1305</c> it should be set to <c>undefined</c> or the
+ <seealso marker="#mac_init-2">mac/2</seealso> function could be used instead, see
+ <seealso marker="algorithm_details#poly1305">Algorithm Details</seealso> in the User's Guide.
+ </item>
+ </list>
+
+ <p><c>Key</c> is the authentication key with a length according to the
+ <c>Type</c> and <c>SubType</c>.
+ The key length could be found with the
+ <seealso marker="#hash_info-1">hash_info/1</seealso> (<c>hmac</c>) for and
+ <seealso marker="#cipher_info-1">cipher_info/1</seealso> (<c>cmac</c>)
+ functions. For <c>poly1305</c> the key length is 32 bytes. Note that
+ the cryptographic quality of the key is not checked.
+ </p>
+
+ <p>The <c>Mac</c> result will have a default length depending on the <c>Type</c> and <c>SubType</c>.
+ To set a shorter length, use <seealso marker="#macN-4">macN/4</seealso> or
+ <seealso marker="#macN-5">macN/5</seealso> instead.
+ The default length is documented in
+ <seealso marker="algorithm_details#message-authentication-codes--macs-">Algorithm Details</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="macN" arity="4" since="OTP @OTP-13872@"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Short for <seealso marker="#macN-5">macN(Type, undefined, Key, Data, MacLength)</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="macN" arity="5" since="OTP @OTP-13872@"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Computes a MAC (Message Authentication Code)
+ as <seealso marker="#mac-3">mac/3</seealso> and <seealso marker="#mac-4">mac/4</seealso> but
+ <c>MacLength</c> will limit the size of the resultant <c>Mac</c> to
+ at most <c>MacLength</c> bytes.
+ Note that if <c>MacLength</c> is greater than the actual number of
+ bytes returned from the underlying hash, the returned hash will have
+ that shorter length instead.
+ </p>
+ <p>The max <c>MacLength</c> is documented in
+ <seealso marker="algorithm_details#message-authentication-codes--macs-">Algorithm Details</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="mac_init" arity="2" since="OTP @OTP-13872@"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Short for <seealso marker="#mac_init-3">mac_init(Type, undefined, Key)</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="mac_init" arity="3" since="OTP @OTP-13872@"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Initializes the context for streaming MAC operations.
+ </p>
+ <p><c>Type</c> determines which mac algorithm to use in the MAC operation.
+ </p>
+
+ <p><c>SubType</c> depends on the MAC <c>Type</c>:
+ </p>
+ <list>
+ <item>For <c>hmac</c> it is a hash algorithm, see
+ <seealso marker="algorithm_details#hmac">Algorithm Details</seealso> in the User's Guide.
+ </item>
+ <item>For <c>cmac</c> it is a cipher suitable for cmac, see
+ <seealso marker="algorithm_details#cmac">Algorithm Details</seealso> in the User's Guide.
+ </item>
+ <item>For <c>poly1305</c> it should be set to <c>undefined</c> or the
+ <seealso marker="#mac_init-2">mac/2</seealso> function could be used instead, see
+ <seealso marker="algorithm_details#poly1305">Algorithm Details</seealso> in the User's Guide.
+ </item>
+ </list>
+
+ <p><c>Key</c> is the authentication key with a length according to the
+ <c>Type</c> and <c>SubType</c>.
+ The key length could be found with the
+ <seealso marker="#hash_info-1">hash_info/1</seealso> (<c>hmac</c>) for and
+ <seealso marker="#cipher_info-1">cipher_info/1</seealso> (<c>cmac</c>)
+ functions. For <c>poly1305</c> the key length is 32 bytes. Note that
+ the cryptographic quality of the key is not checked.
+ </p>
+
+ <p>The returned <c>State</c> should be used in one or more subsequent calls to
+ <seealso marker="#mac_update-2">mac_update/2</seealso>.
+ The MAC value is finally returned by calling
+ <seealso marker="#mac_final-1">mac_final/1</seealso> or
+ <seealso marker="#mac_finalN-2">mac_finalN/2</seealso>.
+ </p>
+
+ <p>See <seealso marker="crypto:new_api#example-of-mac_init-mac_update-and-mac_final">
+ examples in the User's Guide.</seealso>
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="mac_update" arity="2" since="OTP @OTP-13872@"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Updates the MAC represented by <c>State0</c> using the given <c>Data</c> which
+ could be of any length.
+ </p>
+ <p>The <c>State0</c> is the State value originally from a MAC init function, that is
+ <seealso marker="#mac_init-2">mac_init/2</seealso>,
+ <seealso marker="#mac_init-3">mac_init/3</seealso> or
+ a previous call of <c>mac_update/2</c>.
+ The value <c>State0</c> is returned unchanged by the function as <c>State</c>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="mac_final" arity="1" since="OTP @OTP-13872@"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Finalizes the MAC operation referenced by <c>State</c>. The <c>Mac</c> result will have
+ a default length depending on the <c>Type</c> and <c>SubType</c> in the
+ <seealso marker="#mac_init-3">mac_init/2,3</seealso> call.
+ To set a shorter length, use <seealso marker="#mac_finalN-2">mac_finalN/2</seealso> instead.
+ The default length is documented in
+ <seealso marker="algorithm_details#message-authentication-codes--macs-">Algorithm Details</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="mac_finalN" arity="2" since="OTP @OTP-13872@"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Finalizes the MAC operation referenced by <c>State</c>.
+ </p>
+ <p><c>Mac</c> will be a binary with at most <c>MacLength</c> bytes.
+ Note that if <c>MacLength</c> is greater than the actual number of
+ bytes returned from the underlying hash, the returned hash will have
+ that shorter length instead.
+ </p>
+ <p>The max <c>MacLength</c> is documented in
+ <seealso marker="algorithm_details#message-authentication-codes--macs-">Algorithm Details</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
</funcs>
<section>
@@ -886,75 +1079,6 @@
</func>
<func>
- <name name="hmac" arity="3" since="OTP R16B"/>
- <name name="hmac" arity="4" since="OTP R16B"/>
- <fsummary></fsummary>
- <desc>
- <p>Computes a HMAC of type <c>Type</c> from <c>Data</c> using
- <c>Key</c> as the authentication key.</p> <p><c>MacLength</c>
- will limit the size of the resultant <c>Mac</c>.</p>
- </desc>
- </func>
-
- <func>
- <name name="hmac_init" arity="2" since="OTP R14B03"/>
- <fsummary></fsummary>
- <desc>
- <p>Initializes the context for streaming HMAC operations. <c>Type</c> determines
- which hash function to use in the HMAC operation. <c>Key</c> is the authentication
- key. The key can be any length.</p>
- </desc>
- </func>
-
- <func>
- <name name="hmac_update" arity="2" since="OTP R14B03"/>
- <fsummary></fsummary>
- <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>
- or to one of the functions <seealso marker="#hmac_final-1">hmac_final</seealso> and
- <seealso marker="#hmac_final_n-2">hmac_final_n</seealso>
- </p>
- <warning><p>Do not use a <c>Context</c> as argument in more than one
- call to hmac_update or hmac_final. The semantics of reusing old contexts
- in any way is undefined and could even crash the VM in earlier releases.
- The reason for this limitation is a lack of support in the underlying
- libcrypto API.</p></warning>
- </desc>
- </func>
-
- <func>
- <name name="hmac_final" arity="1" since="OTP R14B03"/>
- <fsummary></fsummary>
- <desc>
- <p>Finalizes the HMAC operation referenced by <c>Context</c>. The size of the resultant MAC is
- determined by the type of hash function used to generate it.</p>
- </desc>
- </func>
-
- <func>
- <name name="hmac_final_n" arity="2" since="OTP R14B03"/>
- <fsummary></fsummary>
- <desc>
- <p>Finalizes the HMAC operation referenced by <c>Context</c>. <c>HashLen</c> must be greater than
- 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 name="cmac" arity="3" since="OTP 20.0"/>
- <name name="cmac" arity="4" since="OTP 20.0"/>
- <fsummary>Calculates the Cipher-based Message Authentication Code.</fsummary>
- <desc>
- <p>Computes a CMAC of type <c>Type</c> from <c>Data</c> using
- <c>Key</c> as the authentication key.</p> <p><c>MacLength</c>
- will limit the size of the resultant <c>Mac</c>.</p>
- </desc>
- </func>
-
- <func>
<name name="info_fips" arity="0" since="OTP 20.0"/>
<fsummary>Provides information about the FIPS operating status.</fsummary>
<desc>
@@ -1068,15 +1192,6 @@
</func>
<func>
- <name name="poly1305" arity="2" since="OTP 21.1"/>
- <fsummary></fsummary>
- <desc>
- <p>Computes a POLY1305 message authentication code (<c>Mac</c>) from <c>Data</c> using
- <c>Key</c> as the authentication key.</p>
- </desc>
- </func>
-
- <func>
<name name="private_decrypt" arity="4" since="OTP R16B01"/>
<fsummary>Decrypts CipherText using the private Key.</fsummary>
<desc>
@@ -1961,6 +2076,115 @@ FloatValue = rand:uniform(). % again
</desc>
</func>
+ <func>
+ <name name="hmac" arity="3" since="OTP R16B"/>
+ <name name="hmac" arity="4" since="OTP R16B"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use
+ <seealso marker="crypto#mac-4">mac/4</seealso> or
+ <seealso marker="crypto#macN-5">macN/5</seealso> in
+ <seealso marker="crypto:new_api">the new api</seealso>.</p>
+ </dont>
+ <p>Computes a HMAC of type <c>Type</c> from <c>Data</c> using
+ <c>Key</c> as the authentication key.</p> <p><c>MacLength</c>
+ will limit the size of the resultant <c>Mac</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="hmac_init" arity="2" since="OTP R14B03"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use
+ <seealso marker="crypto#mac_init-3">mac_init/3</seealso> in
+ <seealso marker="crypto:new_api">the new api</seealso>.</p>
+ </dont>
+ <p>Initializes the context for streaming HMAC operations. <c>Type</c> determines
+ which hash function to use in the HMAC operation. <c>Key</c> is the authentication
+ key. The key can be any length.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="hmac_update" arity="2" since="OTP R14B03"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use
+ <seealso marker="crypto#mac_update-2">mac_update/2</seealso> in
+ <seealso marker="crypto:new_api">the new api</seealso>.</p>
+ </dont>
+ <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>
+ or to one of the functions <seealso marker="#hmac_final-1">hmac_final</seealso> and
+ <seealso marker="#hmac_final_n-2">hmac_final_n</seealso>
+ </p>
+ <warning><p>Do not use a <c>Context</c> as argument in more than one
+ call to hmac_update or hmac_final. The semantics of reusing old contexts
+ in any way is undefined and could even crash the VM in earlier releases.
+ The reason for this limitation is a lack of support in the underlying
+ libcrypto API.</p></warning>
+ </desc>
+ </func>
+
+ <func>
+ <name name="hmac_final" arity="1" since="OTP R14B03"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use
+ <seealso marker="crypto#mac_final-1">mac_final/1</seealso> in
+ <seealso marker="crypto:new_api">the new api</seealso>.</p>
+ </dont>
+ <p>Finalizes the HMAC operation referenced by <c>Context</c>. The size of the resultant MAC is
+ determined by the type of hash function used to generate it.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="hmac_final_n" arity="2" since="OTP R14B03"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use
+ <seealso marker="crypto#mac_finalN-2">mac_finalN/2</seealso> in
+ <seealso marker="crypto:new_api">the new api</seealso>.</p>
+ </dont>
+ <p>Finalizes the HMAC operation referenced by <c>Context</c>. <c>HashLen</c> must be greater than
+ 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 name="cmac" arity="3" since="OTP 20.0"/>
+ <name name="cmac" arity="4" since="OTP 20.0"/>
+ <fsummary>Calculates the Cipher-based Message Authentication Code.</fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use
+ <seealso marker="crypto#mac-4">mac/4</seealso> or
+ <seealso marker="crypto#macN-5">macN/5</seealso> in
+ <seealso marker="crypto:new_api">the new api</seealso>.</p>
+ </dont>
+ <p>Computes a CMAC of type <c>Type</c> from <c>Data</c> using
+ <c>Key</c> as the authentication key.</p> <p><c>MacLength</c>
+ will limit the size of the resultant <c>Mac</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="poly1305" arity="2" since="OTP 21.1"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use
+ <seealso marker="crypto#mac-3">mac/3</seealso> or
+ <seealso marker="crypto#macN-4">macN/4</seealso> in
+ <seealso marker="crypto:new_api">the new api</seealso>.</p>
+ </dont>
+ <p>Computes a POLY1305 message authentication code (<c>Mac</c>) from <c>Data</c> using
+ <c>Key</c> as the authentication key.</p>
+ </desc>
+ </func>
+
</funcs>
diff --git a/lib/crypto/doc/src/new_api.xml b/lib/crypto/doc/src/new_api.xml
index bd2334ac9f..aacf5e4f76 100644
--- a/lib/crypto/doc/src/new_api.xml
+++ b/lib/crypto/doc/src/new_api.xml
@@ -40,7 +40,7 @@
to maintain.
</p>
<p>It turned out that using the old api in the new way (more about that later), and still keep it
- backwards compatible, was not possible. Specially as more precision in the error messages was wanted
+ backwards compatible, was not possible. Specially as more precision in the error messages is desired
it could not be combined with the old standard.
</p>
<p>Therefore the old api (see next section) is kept for now but internally implemented with new primitives.
@@ -49,7 +49,7 @@
<section>
<title>The old API</title>
- <p>The old functions - not recommended for new programs - are:</p>
+ <p>The old functions - not recommended for new programs - are for chipers:</p>
<list>
<item><seealso marker="crypto#block_encrypt-3">block_encrypt/3</seealso></item>
<item><seealso marker="crypto#block_encrypt-4">block_encrypt/4</seealso></item>
@@ -59,61 +59,101 @@
<item><seealso marker="crypto#stream_init-2">stream_init/3</seealso></item>
<item><seealso marker="crypto#stream_encrypt-2">stream_encrypt/2</seealso></item>
<item><seealso marker="crypto#stream_decrypt-2">stream_decrypt/2</seealso></item>
+ </list>
+ <p>for lists of supported algorithms:</p>
+ <list>
<item><seealso marker="crypto#supports-0">supports/0</seealso></item>
</list>
+ <p>and for MACs (Message Authentication Codes):</p>
+ <list>
+ <item><seealso marker="crypto#cmac-3">cmac/3</seealso></item>
+ <item><seealso marker="crypto#cmac-4">cmac/4</seealso></item>
+ <item><seealso marker="crypto#hmac-3">hmac/3</seealso></item>
+ <item><seealso marker="crypto#hmac-4">hmac/4</seealso></item>
+ <item><seealso marker="crypto#hmac_init-2">hmac_init/2</seealso></item>
+ <item><seealso marker="crypto#hmac_update-2">hmac_update/2</seealso></item>
+ <item><seealso marker="crypto#hmac_final-1">hmac_final/1</seealso></item>
+ <item><seealso marker="crypto#hmac_final_n-2">hmac_final_n/2</seealso></item>
+ <item><seealso marker="crypto#poly1305-2">poly1305/2</seealso></item>
+ </list>
<p>They are not deprecated for now, but may be in a future release.
</p>
</section>
<section>
<title>The new API</title>
- <p>The new functions for encrypting or decrypting one single binary are:
- </p>
- <list>
- <item><seealso marker="crypto#crypto_one_time/4">crypto_one_time/4</seealso></item>
- <item><seealso marker="crypto#crypto_one_time/5">crypto_one_time/5</seealso></item>
- <item><seealso marker="crypto#crypto_one_time_aead/6">crypto_one_time_aead/6</seealso></item>
- <item><seealso marker="crypto#crypto_one_time_aead/7">crypto_one_time_aead/7</seealso></item>
- </list>
- <p>In those functions the internal crypto state is first created and initialized
- with the cipher type, the key and possibly other data. Then the single binary is encrypted
- or decrypted,
- the crypto state is de-allocated and the result of the crypto operation is returned.
- </p>
- <p>The <c>crypto_one_time_aead</c> functions are for the ciphers of mode <c>ccm</c> or
- <c>gcm</c>, and for the cipher <c>chacha20-poly1305</c>.
- </p>
- <p>For repeated encryption or decryption of a text divided in parts, where the internal
- crypto state is initialized once, and then many binaries are encrypted or decrypted with
- the same state, the functions are:
- </p>
- <list>
- <item><seealso marker="crypto#crypto_init/4">crypto_init/4</seealso></item>
- <item><seealso marker="crypto#crypto_init/3">crypto_init/3</seealso></item>
- <item><seealso marker="crypto#crypto_update/2">crypto_update/2</seealso></item>
- </list>
- <p>The <c>crypto_init</c> initialies an internal cipher state, and one or more calls of
- <c>crypto_update</c> does the acual encryption or decryption. Note that AEAD ciphers
- can't be handled this way due to their nature.
- </p>
- <p>For repeated encryption or decryption of a text divided in parts where the
- same cipher and same key is used, but a new initialization vector (nounce) should be applied
- for each part, the functions are:
- </p>
- <list>
- <item><seealso marker="crypto#crypto_dyn_iv_init/3">crypto_dyn_iv_init/3</seealso></item>
- <item><seealso marker="crypto#crypto_dyn_iv_update/3">crypto_dyn_iv_update/3</seealso></item>
- </list>
- <p>An example of where those functions are needed, is when handling the TLS protocol.</p>
- <p>For information about available algorithms, use:
- </p>
- <list>
- <item><seealso marker="crypto#supports-1">supports/1</seealso></item>
- <item><seealso marker="crypto#hash_info-1">hash_info/1</seealso></item>
- <item><seealso marker="crypto#cipher_info-1">cipher_info/1</seealso></item>
- </list>
+ <section>
+ <title>Encryption and decryption</title>
+ <p>The new functions for encrypting or decrypting one single binary are:
+ </p>
+ <list>
+ <item><seealso marker="crypto#crypto_one_time/4">crypto_one_time/4</seealso></item>
+ <item><seealso marker="crypto#crypto_one_time/5">crypto_one_time/5</seealso></item>
+ <item><seealso marker="crypto#crypto_one_time_aead/6">crypto_one_time_aead/6</seealso></item>
+ <item><seealso marker="crypto#crypto_one_time_aead/7">crypto_one_time_aead/7</seealso></item>
+ </list>
+ <p>In those functions the internal crypto state is first created and initialized
+ with the cipher type, the key and possibly other data. Then the single binary is encrypted
+ or decrypted,
+ the crypto state is de-allocated and the result of the crypto operation is returned.
+ </p>
+ <p>The <c>crypto_one_time_aead</c> functions are for the ciphers of mode <c>ccm</c> or
+ <c>gcm</c>, and for the cipher <c>chacha20-poly1305</c>.
+ </p>
+ <p>For repeated encryption or decryption of a text divided in parts, where the internal
+ crypto state is initialized once, and then many binaries are encrypted or decrypted with
+ the same state, the functions are:
+ </p>
+ <list>
+ <item><seealso marker="crypto#crypto_init/4">crypto_init/4</seealso></item>
+ <item><seealso marker="crypto#crypto_init/3">crypto_init/3</seealso></item>
+ <item><seealso marker="crypto#crypto_update/2">crypto_update/2</seealso></item>
+ </list>
+ <p>The <c>crypto_init</c> initialies an internal cipher state, and one or more calls of
+ <c>crypto_update</c> does the acual encryption or decryption. Note that AEAD ciphers
+ can't be handled this way due to their nature.
+ </p>
+ <p>For repeated encryption or decryption of a text divided in parts where the
+ same cipher and same key is used, but a new initialization vector (nounce) should be applied
+ for each part, the functions are:
+ </p>
+ <list>
+ <item><seealso marker="crypto#crypto_dyn_iv_init/3">crypto_dyn_iv_init/3</seealso></item>
+ <item><seealso marker="crypto#crypto_dyn_iv_update/3">crypto_dyn_iv_update/3</seealso></item>
+ </list>
+ <p>An example of where those functions are needed, is when handling the TLS protocol.</p>
+ <p>For information about available algorithms, use:
+ </p>
+ <list>
+ <item><seealso marker="crypto#supports-1">supports/1</seealso></item>
+ <item><seealso marker="crypto#hash_info-1">hash_info/1</seealso></item>
+ <item><seealso marker="crypto#cipher_info-1">cipher_info/1</seealso></item>
+ </list>
+ </section>
<section>
+ <title>MACs (Message Authentication Codes)</title>
+ <p>The new functions for calculating a MAC of a single piece of text are:</p>
+ <list>
+ <item><seealso marker="crypto#mac-3">mac/3</seealso></item>
+ <item><seealso marker="crypto#mac-4">mac/4</seealso></item>
+ <item><seealso marker="crypto#macN-4">macN/4</seealso></item>
+ <item><seealso marker="crypto#macN-5">macN/5</seealso></item>
+ </list>
+ <p>For calculating a MAC of a text divided in parts use:</p>
+ <list>
+ <item><seealso marker="crypto#mac_init-2">mac_init/2</seealso></item>
+ <item><seealso marker="crypto#mac_init-3">mac_init/3</seealso></item>
+ <item><seealso marker="crypto#mac_update-2">mac_update/2</seealso></item>
+ <item><seealso marker="crypto#mac_final-1">mac_final/1</seealso></item>
+ <item><seealso marker="crypto#mac_finalN-2">mac_finalN/2</seealso></item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Examples of the new api</title>
+ <section>
<title>Examples of crypto_init/4 and crypto_update/2</title>
<p>The functions <seealso marker="crypto#crypto_init/4">crypto_init/4</seealso>
and <seealso marker="crypto#crypto_update/2">crypto_update/2</seealso> are intended
@@ -143,7 +183,7 @@
8> crypto:crypto_update(StateDec, &lt;&lt;67,44,216,166,25,130,203>>).
&lt;&lt;"First b">>
9> crypto:crypto_update(StateDec, &lt;&lt;5,66,6,162,16,79,94,115,234,197,
- 94,253,16,144,151>>).
+ 94,253,16,144,151>>).
&lt;&lt;"ytesSecond byte">>
10> crypto:crypto_update(StateDec, &lt;&lt;41>>).
&lt;&lt;"s">>
@@ -159,16 +199,16 @@
</p>
<code type="erl">
encode(Crypto, Key, IV) ->
- crypto_loop(crypto:crypto_init(Crypto, Key, IV, true)).
+ crypto_loop(crypto:crypto_init(Crypto, Key, IV, true)).
crypto_loop(State) ->
- receive
- {Text, Requester} ->
- Requester ! crypto:crypto_update(State, Text),
- loop(State)
- end.
+ receive
+ {Text, Requester} ->
+ Requester ! crypto:crypto_update(State, Text),
+ loop(State)
+ end.
</code>
- </section>
+ </section>
<section>
<title>Example of crypto_one_time/5</title>
@@ -219,6 +259,35 @@
</p>
</section>
+ <section>
+ <title>Example of mac_init mac_update and mac_final</title>
+ <code>
+ 1> Key = &lt;&lt;1:128>>.
+ &lt;&lt;0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>
+ 2> StateMac = crypto:mac_init(cmac, aes_128_cbc, Key).
+ #Ref&lt;0.2424664121.2781478916.232610>
+ 3> crypto:mac_update(StateMac, &lt;&lt;"First bytes">>).
+ #Ref&lt;0.2424664121.2781478916.232610>
+ 4> crypto:mac_update(StateMac, " ").
+ #Ref&lt;0.2424664121.2781478916.232610>
+ 5> crypto:mac_update(StateMac, &lt;&lt;"last bytes">>).
+ #Ref&lt;0.2424664121.2781478916.232610>
+ 6> crypto:mac_final(StateMac).
+ &lt;&lt;68,191,219,128,84,77,11,193,197,238,107,6,214,141,160,
+ 249>>
+ 7>
+ </code>
+ <p>and compare the result with a single calculation just for this example:</p>
+ <code>
+ 7> crypto:mac(cmac, aes_128_cbc, Key, "First bytes last bytes").
+ &lt;&lt;68,191,219,128,84,77,11,193,197,238,107,6,214,141,160,
+ 249>>
+ 8> v(7) == v(6).
+ true
+ 9>
+ </code>
+ </section>
+
</section>
<section>
@@ -233,7 +302,7 @@
on the mode. An example is the ccm mode which has a variant called ccm8 where the so called tag
has a length of eight bits.
</p>
- <p>The old names had by time lost any common naming which the new names now introduces. The new names include
+ <p>The old names had by time lost any common naming convention which the new names now introduces. The new names include
the key length which improves the error checking in the lower levels of the crypto application.
</p>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 8ffdde2b90..965697578d 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -28,9 +28,6 @@
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
-export([sign/4, sign/5, verify/5, verify/6]).
-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([cmac/3, cmac/4]).
--export([poly1305/2]).
-export([exor/2, strong_rand_bytes/1, mod_pow/3]).
-export([rand_seed/0, rand_seed_alg/1, rand_seed_alg/2]).
-export([rand_seed_s/0, rand_seed_alg_s/1, rand_seed_alg_s/2]).
@@ -48,6 +45,9 @@
-export([rand_seed/1]).
%% Old interface. Now implemented with the New interface
+-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-export([cmac/3, cmac/4]).
+-export([poly1305/2]).
-export([stream_init/2, stream_init/3,
stream_encrypt/2,
stream_decrypt/2,
@@ -62,7 +62,9 @@
crypto_one_time_aead/6, crypto_one_time_aead/7,
crypto_dyn_iv_init/3,
crypto_dyn_iv_update/3,
- supports/1
+ supports/1,
+ mac/3, mac/4, macN/4, macN/5,
+ mac_init/2, mac_init/3, mac_update/2, mac_final/1, mac_finalN/2
]).
@@ -109,9 +111,10 @@
stream_state/0,
hmac_state/0,
hash_state/0,
- crypto_state/0
+ crypto_state/0,
+ mac_state/0
]).
-
+
%% Private. For tests.
-export([packed_openssl_version/4, engine_methods_convert_to_bitmask/2,
get_test_engine/0]).
@@ -136,7 +139,7 @@
-type rsa_private() :: [key_integer()] . % [E, N, D] | [E, N, D, P1, P2, E1, E2, C]
-type rsa_params() :: {ModulusSizeInBits::integer(), PublicExponent::key_integer()} .
--type dss_public() :: [key_integer()] . % [P, Q, G, Y]
+-type dss_public() :: [key_integer()] . % [P, Q, G, Y]
-type dss_private() :: [key_integer()] . % [P, Q, G, X]
-type ecdsa_public() :: key_integer() .
@@ -282,7 +285,7 @@
%%% New cipher schema
%%%
-type cipher() :: cipher_no_iv()
- | cipher_iv()
+ | cipher_iv()
| cipher_aead() .
-type cipher_no_iv() :: aes_128_ecb
@@ -326,7 +329,7 @@
-type cipher_aead() :: aes_128_ccm
| aes_192_ccm
| aes_256_ccm
-
+
| aes_128_gcm
| aes_192_gcm
| aes_256_gcm
@@ -334,23 +337,6 @@
| chacha20_poly1305 .
-%% -type retired_cipher_no_iv_aliases() :: aes_ecb .
-
-%% -type retired_cipher_iv_aliases() :: aes_cbc
-%% | aes_cbc128 % aes_128_cbc
-%% | aes_cbc256 % aes_256_cbc
-%% | aes_cfb128
-%% | aes_cfb8
-%% | aes_ctr
-%% | des3_cbc % des_ede3_cbc
-%% | des_ede3 % des_ede3_cbc
-%% | des_ede3_cbf % des_ede3_cfb
-%% | des3_cbf % des_ede3_cfb
-%% | des3_cfb . % des_ede3_cfb
-
-%% -type retired_cipher_aead_aliases() :: aes_ccm
-%% | aes_gcm .
-
%%%----------------------------------------------------------------
%%% Old cipher scheme
%%%
@@ -365,7 +351,7 @@
-type stream_cipher() :: ctr_cipher()
| chacha20
| rc4 .
-
+
%%%----
-type cbc_cipher() :: aes_128_cbc
@@ -374,7 +360,7 @@
| blowfish_cbc
| des_cbc
| des_ede3_cbc
- | rc2_cbc
+ | rc2_cbc
| retired_cbc_cipher_aliases() .
-type retired_cbc_cipher_aliases() :: aes_cbc % aes_*_cbc
@@ -382,7 +368,7 @@
| aes_cbc256 % aes_256_cbc
| des3_cbc % des_ede3_cbc
| des_ede3 . % des_ede3_cbc
-
+
%%%----
-type cfb_cipher() :: aes_128_cfb128
| aes_192_cfb128
@@ -398,7 +384,7 @@
-type retired_cfb_cipher_aliases() :: aes_cfb8 % aes_*_cfb8
| aes_cfb128 % aes_*_cfb128
| des3_cbf % des_ede3_cfb, cfb misspelled
- | des3_cfb % des_ede3_cfb
+ | des3_cfb % des_ede3_cfb
| des_ede3_cbf .% cfb misspelled
@@ -457,6 +443,19 @@
%%--------------------------------------------------------------------
+%%
+%% Make the new descriptive_error() look like the old run_time_error()
+%%
+-define(COMPAT(CALL),
+ try begin CALL end
+ catch
+ error:{error, {_File,_Line}, _Reason} ->
+ error(badarg);
+ error:{E, {_File,_Line}, _Reason} when E==notsup ; E==badarg ->
+ error(E)
+ end).
+
+%%--------------------------------------------------------------------
-compile(no_native).
-on_load(on_load/0).
-define(CRYPTO_NIF_VSN,302).
@@ -580,7 +579,7 @@ hash(Type, Data) ->
-spec hash_init(Type) -> State when Type :: hash_algorithm(),
State :: hash_state().
-hash_init(Type) ->
+hash_init(Type) ->
notsup_to_error(hash_init_nif(Type)).
-spec hash_update(State, Data) -> NewState when State :: hash_state(),
@@ -599,25 +598,139 @@ hash_final(Context) ->
%%%================================================================
%%%
%%% MACs (Message Authentication Codes)
-%%%
+%%%
%%%================================================================
-%%%---- HMAC
-
-type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash().
-%%%---- hmac/3,4
+-type cmac_cipher_algorithm() :: aes_128_cbc | aes_192_cbc | aes_256_cbc | blowfish_cbc
+ | des_cbc | des_ede3_cbc | rc2_cbc
+ | aes_128_cfb128 | aes_192_cfb128 | aes_256_cfb128
+ | aes_128_cfb8 | aes_192_cfb8 | aes_256_cfb8
+ .
+
+%%%----------------------------------------------------------------
+%%% Calculate MAC for the whole text at once
+
+-spec mac(Type :: poly1305, Key, Data) -> Mac | descriptive_error()
+ when Key :: iodata(),
+ Data :: iodata(),
+ Mac :: binary().
+
+mac(poly1305, Key, Data) -> mac(poly1305, undefined, Key, Data).
+
+
+-spec mac(Type, SubType, Key, Data) -> Mac | descriptive_error()
+ when Type :: hmac | cmac | poly1305,
+ SubType :: hmac_hash_algorithm() | cmac_cipher_algorithm() | undefined,
+ Key :: iodata(),
+ Data :: iodata(),
+ Mac :: binary().
+
+mac(Type, SubType, Key, Data) -> mac_nif(Type, SubType, Key, Data).
+
+
+
+-spec macN(Type :: poly1305, Key, Data, MacLength) -> Mac | descriptive_error()
+ when Key :: iodata(),
+ Data :: iodata(),
+ Mac :: binary(),
+ MacLength :: pos_integer().
+
+macN(Type, Key, Data, MacLength) ->
+ macN(Type, undefined, Key, Data, MacLength).
+
+
+-spec macN(Type, SubType, Key, Data, MacLength) -> Mac | descriptive_error()
+ when Type :: hmac | cmac | poly1305,
+ SubType :: hmac_hash_algorithm() | cmac_cipher_algorithm() | undefined,
+ Key :: iodata(),
+ Data :: iodata(),
+ Mac :: binary(),
+ MacLength :: pos_integer().
+
+macN(Type, SubType, Key, Data, MacLength) ->
+ erlang:binary_part(mac(Type,SubType,Key,Data), 0, MacLength).
+
+
+%%%----------------------------------------------------------------
+%%% Calculate the MAC by uppdating by pieces of the text
+
+-opaque mac_state() :: reference() .
+
+-spec mac_init(Type :: poly1305, Key) -> State | descriptive_error()
+ when Key :: iodata(),
+ State :: mac_state() .
+mac_init(poly1305, Key) ->
+ mac_init_nif(poly1305, undefined, Key).
+
+
+-spec mac_init(Type, SubType, Key) -> State | descriptive_error()
+ when Type :: hmac | cmac | poly1305,
+ SubType :: hmac_hash_algorithm() | cmac_cipher_algorithm() | undefined,
+ Key :: iodata(),
+ State :: mac_state() .
+mac_init(Type, SubType, Key) ->
+ mac_init_nif(Type, SubType, Key).
+
+
+-spec mac_update(State0, Data) -> State | descriptive_error()
+ when Data :: iodata(),
+ State0 :: mac_state(),
+ State :: mac_state().
+mac_update(Ref, Data) ->
+ mac_update_nif(Ref, Data).
+
+
+
+-spec mac_final(State) -> Mac | descriptive_error()
+ when State :: mac_state(),
+ Mac :: binary().
+mac_final(Ref) ->
+ mac_final_nif(Ref).
+
+
+-spec mac_finalN(State, MacLength) -> Mac | descriptive_error()
+ when State :: mac_state(),
+ MacLength :: pos_integer(),
+ Mac :: binary().
+mac_finalN(Ref, MacLength) ->
+ erlang:binary_part(mac_final(Ref), 0, MacLength).
+
--spec hmac(Type, Key, Data) ->
+%%%----------------------------------------------------------------
+%%% NIFs for the functions above
+
+mac_nif(_Type, _SubType, _Key, _Data) -> ?nif_stub.
+
+mac_init_nif(_Type, _SubType, _Key) -> ?nif_stub.
+mac_update_nif(_Ref, _Data) -> ?nif_stub.
+mac_final_nif(_Ref) -> ?nif_stub.
+
+%%%================================================================
+%%%
+%%% The "Old API", kept for compatibility
+%%%
+%%%================================================================
+
+%%%----------------------------------------------------------------
+%%%----------------------------------------------------------------
+%%% Message Authentication Codes, MAC
+%%%
+
+%%%---- HMAC
+
+%%%---- hmac/3,4
+
+-spec hmac(Type, Key, Data) ->
Mac when Type :: hmac_hash_algorithm(),
Key :: iodata(),
Data :: iodata(),
Mac :: binary() .
hmac(Type, Key, Data) ->
- Data1 = iolist_to_binary(Data),
- hmac(Type, Key, Data1, undefined, erlang:byte_size(Data1), max_bytes()).
+ ?COMPAT(mac(hmac, Type, Key, Data)).
--spec hmac(Type, Key, Data, MacLength) ->
+-spec hmac(Type, Key, Data, MacLength) ->
Mac when Type :: hmac_hash_algorithm(),
Key :: iodata(),
Data :: iodata(),
@@ -625,45 +738,43 @@ hmac(Type, Key, Data) ->
Mac :: binary() .
hmac(Type, Key, Data, MacLength) ->
- Data1 = iolist_to_binary(Data),
- hmac(Type, Key, Data1, MacLength, erlang:byte_size(Data1), max_bytes()).
+ ?COMPAT(macN(hmac, Type, Key, Data, MacLength)).
%%%---- hmac_init, hamc_update, hmac_final
--opaque hmac_state() :: binary().
+-opaque hmac_state() :: mac_state(). % Was: binary().
-spec hmac_init(Type, Key) ->
State when Type :: hmac_hash_algorithm(),
Key :: iodata(),
State :: hmac_state() .
hmac_init(Type, Key) ->
- notsup_to_error(hmac_init_nif(Type, Key)).
+ ?COMPAT(mac_init(hmac, Type, Key)).
%%%---- hmac_update
-spec hmac_update(State, Data) -> NewState when Data :: iodata(),
State :: hmac_state(),
NewState :: hmac_state().
-hmac_update(State, Data0) ->
- Data = iolist_to_binary(Data0),
- hmac_update(State, Data, erlang:byte_size(Data), max_bytes()).
+hmac_update(State, Data) ->
+ ?COMPAT(mac_update(State, Data)).
%%%---- hmac_final
-spec hmac_final(State) -> Mac when State :: hmac_state(),
Mac :: binary().
hmac_final(Context) ->
- notsup_to_error(hmac_final_nif(Context)).
+ ?COMPAT(mac_final(Context)).
-spec hmac_final_n(State, HashLen) -> Mac when State :: hmac_state(),
HashLen :: integer(),
Mac :: binary().
hmac_final_n(Context, HashLen) ->
- notsup_to_error(hmac_final_nif(Context, HashLen)).
+ ?COMPAT(mac_finalN(Context, HashLen)).
%%%---- CMAC
--define(CMAC_CIPHER_ALGORITHM, cbc_cipher() | cfb_cipher() | blowfish_cbc | des_ede3 | rc2_cbc ).
+-define(CMAC_CIPHER_ALGORITHM, cbc_cipher() | cfb_cipher() | blowfish_cbc | des_ede3 | rc2_cbc ).
-spec cmac(Type, Key, Data) ->
Mac when Type :: ?CMAC_CIPHER_ALGORITHM,
@@ -671,42 +782,31 @@ hmac_final_n(Context, HashLen) ->
Data :: iodata(),
Mac :: binary().
cmac(Type, Key, Data) ->
- notsup_to_error(cmac_nif(alias(Type), Key, Data)).
+ ?COMPAT(mac(cmac, alias(Type), Key, Data)).
-spec cmac(Type, Key, Data, MacLength) ->
Mac when Type :: ?CMAC_CIPHER_ALGORITHM,
Key :: iodata(),
Data :: iodata(),
- MacLength :: integer(),
+ MacLength :: integer(),
Mac :: binary().
cmac(Type, Key, Data, MacLength) ->
- erlang:binary_part(cmac(alias(Type), Key, Data), 0, MacLength).
+ ?COMPAT(macN(cmac, alias(Type), Key, Data, MacLength)).
%%%---- POLY1305
-spec poly1305(iodata(), iodata()) -> Mac when Mac :: binary().
poly1305(Key, Data) ->
- poly1305_nif(Key, Data).
+ ?COMPAT(mac(poly1305, Key, Data)).
-%%%================================================================
-%%%
-%%% Encrypt/decrypt, The "Old API"
-%%%
-%%%================================================================
+%%%----------------------------------------------------------------
+%%%----------------------------------------------------------------
+%%% Ciphers
--define(COMPAT(CALL),
- try begin CALL end
- catch
- error:{error, {_File,_Line}, _Reason} ->
- error(badarg);
- error:{E, {_File,_Line}, _Reason} when E==notsup ; E==badarg ->
- error(E)
- end).
%%%---- Cipher info
-%%%----------------------------------------------------------------
-spec cipher_info(Type) -> Result | run_time_error()
when Type :: cipher(),
Result :: #{key_length := integer(),
@@ -845,7 +945,7 @@ block_decrypt(Type, Key0, CryptoText) ->
Key :: iodata(),
IVec ::binary(),
State :: stream_state() .
-stream_init(Type, Key0, IVec) when is_binary(IVec) ->
+stream_init(Type, Key0, IVec) when is_binary(IVec) ->
Key = iolist_to_binary(Key0),
Ref = ?COMPAT(ng_crypto_init_nif(alias(Type,Key),
Key, iolist_to_binary(IVec),
@@ -933,7 +1033,7 @@ next_iv(Type, Data, _Ivec) ->
%%%----------------------------------------------------------------
%%%
%%% Create and initialize a new state for encryption or decryption
-%%%
+%%%
-spec crypto_init(Cipher, Key, EncryptFlag) -> State | descriptive_error()
when Cipher :: cipher_no_iv(),
@@ -971,12 +1071,12 @@ crypto_dyn_iv_init(Cipher, Key, EncryptFlag) ->
%%% Encrypt/decrypt a sequence of bytes. The sum of the sizes
%%% of all blocks must be an integer multiple of the crypto's
%%% blocksize.
-%%%
+%%%
-spec crypto_update(State, Data) -> Result | descriptive_error()
- when State :: crypto_state(),
- Data :: iodata(),
- Result :: binary() .
+ when State :: crypto_state(),
+ Data :: iodata(),
+ Result :: binary() .
crypto_update(State, Data0) ->
case iolist_to_binary(Data0) of
<<>> ->
@@ -1005,7 +1105,7 @@ crypto_dyn_iv_update(State, Data0, IV) ->
%%%
%%% Encrypt/decrypt one set bytes.
%%% The size must be an integer multiple of the crypto's blocksize.
-%%%
+%%%
-spec crypto_one_time(Cipher, Key, Data, EncryptFlag) ->
Result | descriptive_error()
@@ -1015,8 +1115,15 @@ crypto_dyn_iv_update(State, Data0, IV) ->
EncryptFlag :: boolean(),
Result :: binary() .
-crypto_one_time(Cipher, Key, Data, EncryptFlag) ->
- crypto_one_time(Cipher, Key, <<>>, Data, EncryptFlag).
+crypto_one_time(Cipher, Key, Data0, EncryptFlag) ->
+ case iolist_to_binary(Data0) of
+ <<>> ->
+ <<>>; % Known to fail on OpenSSL 0.9.8h
+ Data ->
+ ng_crypto_one_time_nif(Cipher,
+ iolist_to_binary(Key), <<>>, Data,
+ EncryptFlag)
+ end.
-spec crypto_one_time(Cipher, Key, IV, Data, EncryptFlag) ->
Result | descriptive_error()
@@ -1121,7 +1228,7 @@ ng_crypto_one_time_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?nif_stub.
false ->
Ciphers
end).
-
+
prepend_old_aliases(L0) ->
L1 = ?if_also(des_ede3_cbc, L0,
@@ -1465,7 +1572,7 @@ rand_seed_nif(_Seed) -> ?nif_stub.
%%% Sign
-spec sign(Algorithm, DigestType, Msg, Key)
- -> Signature
+ -> Signature
when Algorithm :: pk_sign_verify_algs(),
DigestType :: rsa_digest_type()
| dss_digest_type()
@@ -1483,7 +1590,7 @@ sign(Algorithm, Type, Data, Key) ->
-spec sign(Algorithm, DigestType, Msg, Key, Options)
- -> Signature
+ -> Signature
when Algorithm :: pk_sign_verify_algs(),
DigestType :: rsa_digest_type()
| dss_digest_type()
@@ -1580,7 +1687,7 @@ sign_verify_compatibility(Algorithm0, Type0, _Digest) ->
| rsa_x931_padding
| rsa_no_padding.
--type rsa_opt() :: {rsa_padding, rsa_padding()}
+-type rsa_opt() :: {rsa_padding, rsa_padding()}
| {signature_md, atom()}
| {rsa_mgf1_md, sha}
| {rsa_oaep_label, binary()}
@@ -1653,7 +1760,7 @@ pkey_crypt_nif(_Algorithm, _In, _Key, _Options, _IsPrivate, _IsEncrypt) -> ?nif_
%%%================================================================
-spec generate_key(Type, Params)
- -> {PublicKey, PrivKeyOut}
+ -> {PublicKey, PrivKeyOut}
when Type :: dh | ecdh | rsa | srp,
PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(),
PrivKeyOut :: dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
@@ -1663,7 +1770,7 @@ generate_key(Type, Params) ->
generate_key(Type, Params, undefined).
-spec generate_key(Type, Params, PrivKeyIn)
- -> {PublicKey, PrivKeyOut}
+ -> {PublicKey, PrivKeyOut}
when Type :: dh | ecdh | rsa | srp,
PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(),
PrivKeyIn :: undefined | dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
@@ -1814,7 +1921,7 @@ mod_pow(Base, Exponent, Prime) ->
%%%======================================================================
%%%
%%% Engine functions
-%%%
+%%%
%%%======================================================================
%%%---- Refering to keys stored in an engine:
@@ -2121,7 +2228,7 @@ ensure_engine_unloaded(Engine) ->
%%----------------------------------------------------------------------
%% Function: ensure_engine_unloaded/2
%%----------------------------------------------------------------------
--spec ensure_engine_unloaded(Engine, EngineMethods) ->
+-spec ensure_engine_unloaded(Engine, EngineMethods) ->
Result when Engine :: engine_ref(),
EngineMethods :: [engine_method_type()],
Result :: ok | {error, Reason::term()}.
@@ -2203,7 +2310,7 @@ path2bin(Path) when is_list(Path) ->
%%%================================================================
%%%
%%% Internal functions
-%%%
+%%%
%%%================================================================
max_bytes() ->
@@ -2235,43 +2342,6 @@ hash_init_nif(_Hash) -> ?nif_stub.
hash_update_nif(_State, _Data) -> ?nif_stub.
hash_final_nif(_State) -> ?nif_stub.
-%% HMAC --------------------------------------------------------------------
-
-hmac(Type, Key, Data, MacSize, Size, MaxBytes) when Size =< MaxBytes ->
- notsup_to_error(
- case MacSize of
- undefined -> hmac_nif(Type, Key, Data);
- _ -> hmac_nif(Type, Key, Data, MacSize)
- end);
-hmac(Type, Key, Data, MacSize, Size, MaxBytes) ->
- State0 = hmac_init(Type, Key),
- State1 = hmac_update(State0, Data, Size, MaxBytes),
- case MacSize of
- undefined -> hmac_final(State1);
- _ -> hmac_final_n(State1, MacSize)
- end.
-
-hmac_update(State, Data, Size, MaxBytes) when Size =< MaxBytes ->
- notsup_to_error(hmac_update_nif(State, Data));
-hmac_update(State0, Data, _, MaxBytes) ->
- <<Increment:MaxBytes/binary, Rest/binary>> = Data,
- State = notsup_to_error(hmac_update_nif(State0, Increment)),
- hmac_update(State, Rest, erlang:byte_size(Rest), MaxBytes).
-
-hmac_nif(_Type, _Key, _Data) -> ?nif_stub.
-hmac_nif(_Type, _Key, _Data, _MacSize) -> ?nif_stub.
-hmac_init_nif(_Type, _Key) -> ?nif_stub.
-hmac_update_nif(_Context, _Data) -> ?nif_stub.
-hmac_final_nif(_Context) -> ?nif_stub.
-hmac_final_nif(_Context, _MacSize) -> ?nif_stub.
-
-%% CMAC
-cmac_nif(_Type, _Key, _Data) -> ?nif_stub.
-
-%% POLY1305
-poly1305_nif(_Key, _Data) -> ?nif_stub.
-
-
%% CIPHERS --------------------------------------------------------------------
cipher_info_nif(_Type) -> ?nif_stub.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 56691223c4..0da70d5592 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -176,19 +176,19 @@ groups() ->
]},
{md4, [], [hash]},
- {md5, [], [hash, hmac]},
+ {md5, [], [hash, hmac, hmac_update]},
{ripemd160, [], [hash]},
- {sha, [], [hash, hmac]},
- {sha224, [], [hash, hmac]},
- {sha256, [], [hash, hmac]},
- {sha384, [], [hash, hmac]},
- {sha512, [], [hash, hmac]},
- {sha3_224, [], [hash, hmac]},
- {sha3_256, [], [hash, hmac]},
- {sha3_384, [], [hash, hmac]},
- {sha3_512, [], [hash, hmac]},
- {blake2b, [], [hash, hmac]},
- {blake2s, [], [hash, hmac]},
+ {sha, [], [hash, hmac, hmac_update]},
+ {sha224, [], [hash, hmac, hmac_update]},
+ {sha256, [], [hash, hmac, hmac_update]},
+ {sha384, [], [hash, hmac, hmac_update]},
+ {sha512, [], [hash, hmac, hmac_update]},
+ {sha3_224, [], [hash, hmac, hmac_update]},
+ {sha3_256, [], [hash, hmac, hmac_update]},
+ {sha3_384, [], [hash, hmac, hmac_update]},
+ {sha3_512, [], [hash, hmac, hmac_update]},
+ {blake2b, [], [hash, hmac, hmac_update]},
+ {blake2s, [], [hash, hmac, hmac_update]},
{no_blake2b, [], [no_hash, no_hmac]},
{no_blake2s, [], [no_hash, no_hmac]},
{rsa, [], [sign_verify,
@@ -265,9 +265,9 @@ groups() ->
%% New cipher nameing schema
{des_ede3_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{des_ede3_cfb, [], [api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_128_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_128_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac]},
{aes_192_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_256_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_256_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac]},
{aes_128_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_192_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_256_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
@@ -386,7 +386,7 @@ init_per_testcase(info, Config) ->
init_per_testcase(cmac, Config) ->
case is_supported(cmac) of
true ->
- Config;
+ configure_mac(cmac, proplists:get_value(type,Config), Config);
false ->
{skip, "CMAC is not supported"}
end;
@@ -405,6 +405,8 @@ init_per_testcase(generate, Config) ->
end;
_ -> Config
end;
+init_per_testcase(hmac, Config) ->
+ configure_mac(hmac, proplists:get_value(type,Config), Config);
init_per_testcase(_Name,Config) ->
Config.
@@ -452,27 +454,41 @@ no_hash(Config) when is_list(Config) ->
notsup(fun crypto:hash_init/1, [Type]).
%%--------------------------------------------------------------------
hmac() ->
- [{doc, "Test all different hmac functions"}].
+ [{doc, "Test hmac function"}].
hmac(Config) when is_list(Config) ->
- {Type, Keys, DataLE, Expected} = proplists:get_value(hmac, Config),
- Data = lazy_eval(DataLE),
- hmac(Type, Keys, Data, Expected),
- hmac(Type, lists:map(fun iolistify/1, Keys), lists:map(fun iolistify/1, Data), Expected),
- hmac_increment(Type).
+ Tuples = lazy_eval(proplists:get_value(hmac, Config)),
+ lists:foreach(fun hmac_check/1, Tuples),
+ lists:foreach(fun hmac_check/1, mac_listify(Tuples)).
+
%%--------------------------------------------------------------------
no_hmac() ->
[{doc, "Test all disabled hmac functions"}].
no_hmac(Config) when is_list(Config) ->
Type = ?config(type, Config),
- notsup(fun crypto:hmac/3, [Type, <<"Key">>, <<"Hi There">>]),
+ notsup(fun crypto:hmac/3, [Type, <<"Key">>, <<"Hi There">>]).
+
+%%--------------------------------------------------------------------
+hmac_update() ->
+ [{doc, "Test all incremental hmac functions"}].
+hmac_update(Config) ->
+ Type = ?config(type, Config),
+ hmac_increment(Type).
+
+%%--------------------------------------------------------------------
+no_hmac_update() ->
+ [{doc, "Test all disabled incremental hmac functions"}].
+no_hmac_update(Config) ->
+ Type = ?config(type, Config),
notsup(fun crypto:hmac_init/2, [Type, <<"Key">>]).
+
%%--------------------------------------------------------------------
cmac() ->
[{doc, "Test all different cmac functions"}].
cmac(Config) when is_list(Config) ->
Pairs = lazy_eval(proplists:get_value(cmac, Config)),
lists:foreach(fun cmac_check/1, Pairs),
- lists:foreach(fun cmac_check/1, cmac_iolistify(Pairs)).
+ lists:foreach(fun cmac_check/1, mac_listify(Pairs)).
+
%%--------------------------------------------------------------------
poly1305() ->
[{doc, "Test poly1305 function"}].
@@ -957,33 +973,46 @@ hash_increment(State0, [Increment | Rest]) ->
State = crypto:hash_update(State0, Increment),
hash_increment(State, Rest).
-hmac(_, [],[],[]) ->
- ok;
-hmac(sha = Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
- call_crypto_hmac([Type, Key, Data, 20], Type, Expected),
- hmac(Type, Keys, Rest, Expects);
-hmac(Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
- call_crypto_hmac([Type, Key, Data, 16], Type, Expected),
- hmac(Type, Keys, Rest, Expects);
-hmac(Type, [Key | Keys], [Data| Rest], [Expected | Expects]) ->
- call_crypto_hmac([Type, Key, Data], Type, Expected),
- hmac(Type, Keys, Rest, Expects).
-
-call_crypto_hmac(Args, Type, Expected) ->
- try apply(crypto, hmac, Args)
+
+%%%----------------------------------------------------------------
+hmac_check({hmac, sha=Type, Key, <<"Test With Truncation">>=Data, Expected}) ->
+ do_hmac_check(Type, Key, Data, 20, Expected);
+hmac_check({hmac, Type, Key, <<"Test With Truncation">>=Data, Expected}) ->
+ do_hmac_check(Type, Key, Data, 16, Expected);
+hmac_check({hmac, Type, Key, Data, Expected}) ->
+ do_hmac_check(Type, Key, Data, Expected).
+
+
+do_hmac_check(Type, Key, Data, Expected) ->
+ try crypto:hmac(Type, Key, Data)
of
Expected ->
ok;
Other ->
- ct:fail({{crypto,hmac,Args}, {expected,Expected}, {got,Other}})
+ ct:fail({{crypto,hmac,[Type,Key,Data]}, {expected,Expected}, {got,Other}})
catch
error:notsup ->
ct:fail("HMAC ~p not supported", [Type]);
Class:Cause ->
- ct:fail({{crypto,hmac,Args}, {expected,Expected}, {got,{Class,Cause}}})
+ ct:fail({{crypto,hmac,[Type,Key,Data]}, {expected,Expected}, {got,{Class,Cause}}})
end.
+do_hmac_check(Type, Key, Data, MacLength, Expected) ->
+ try crypto:hmac(Type, Key, Data, MacLength)
+ of
+ Expected ->
+ ok;
+ Other ->
+ ct:fail({{crypto,hmac,[Type,Key,Data,MacLength]}, {expected,Expected}, {got,Other}})
+ catch
+ error:notsup ->
+ ct:fail("HMAC ~p not supported", [Type]);
+ Class:Cause ->
+ ct:fail({{crypto,hmac,[Type,Key,Data,MacLength]}, {expected,Expected}, {got,{Class,Cause}}})
+ end.
+
+%%%----------------------------------------------------------------
hmac_increment(Type) ->
Key = hmac_key(Type),
Increments = hmac_inc(Type),
@@ -1002,7 +1031,8 @@ hmac_increment(State0, [Increment | Rest]) ->
State = crypto:hmac_update(State0, Increment),
hmac_increment(State, Rest).
-cmac_check({Type, Key, Text, CMac}) ->
+%%%----------------------------------------------------------------
+cmac_check({cmac, Type, Key, Text, CMac}) ->
ExpCMac = iolist_to_binary(CMac),
case crypto:cmac(Type, Key, Text) of
ExpCMac ->
@@ -1010,7 +1040,7 @@ cmac_check({Type, Key, Text, CMac}) ->
Other ->
ct:fail({{crypto, cmac, [Type, Key, Text]}, {expected, ExpCMac}, {got, Other}})
end;
-cmac_check({Type, Key, Text, Size, CMac}) ->
+cmac_check({cmac, Type, Key, Text, Size, CMac}) ->
ExpCMac = iolist_to_binary(CMac),
case crypto:cmac(Type, Key, Text, Size) of
ExpCMac ->
@@ -1020,6 +1050,24 @@ cmac_check({Type, Key, Text, Size, CMac}) ->
end.
+mac_check({MacType, SubType, Key, Text, Mac}) ->
+ ExpMac = iolist_to_binary(Mac),
+ case crypto:mac(MacType, SubType, Key, Text) of
+ ExpMac ->
+ ok;
+ Other ->
+ ct:fail({{crypto, mac, [MacType, SubType, Key, Text]}, {expected, ExpMac}, {got, Other}})
+ end;
+mac_check({MacType, SubType, Key, Text, Size, Mac}) ->
+ ExpMac = iolist_to_binary(Mac),
+ case crypto:mac(MacType, SubType, Key, Text, Size) of
+ ExpMac ->
+ ok;
+ Other ->
+ ct:fail({{crypto, mac, [MacType, SubType, Key, Text]}, {expected, ExpMac}, {got, Other}})
+ end.
+
+
block_cipher({Type, Key, PlainText}) ->
Plain = iolist_to_binary(PlainText),
CipherText = crypto:block_encrypt(Type, Key, PlainText),
@@ -1450,17 +1498,17 @@ decstr2int(S) ->
is_supported(Group) ->
lists:member(Group, lists:append([Algo || {_, Algo} <- crypto:supports()])).
-cmac_iolistify(Blocks) ->
- lists:map(fun do_cmac_iolistify/1, Blocks).
+mac_listify(Blocks) ->
+ lists:map(fun do_mac_listify/1, Blocks).
block_iolistify(Blocks) ->
lists:map(fun do_block_iolistify/1, Blocks).
stream_iolistify(Streams) ->
lists:map(fun do_stream_iolistify/1, Streams).
-do_cmac_iolistify({Type, Key, Text, CMac}) ->
- {Type, iolistify(Key), iolistify(Text), CMac};
-do_cmac_iolistify({Type, Key, Text, Size, CMac}) ->
- {Type, iolistify(Key), iolistify(Text), Size, CMac}.
+do_mac_listify({MType, Type, Key, Text, CMac}) ->
+ {MType, Type, iolistify(Key), iolistify(Text), CMac};
+do_mac_listify({MType, Type, Key, Text, Size, CMac}) ->
+ {MType, Type, iolistify(Key), iolistify(Text), Size, CMac}.
do_stream_iolistify({Type, Key, PlainText}) ->
{Type, iolistify(Key), iolistify(PlainText)};
@@ -1694,10 +1742,7 @@ group_config(md4 = Type, Config) ->
group_config(md5 = Type, Config) ->
Msgs = rfc_1321_msgs(),
Digests = rfc_1321_md5_digests(),
- Keys = rfc_2202_md5_keys() ++ [long_hmac_key(md5)],
- Data = rfc_2202_msgs() ++ [long_msg()],
- Hmac = rfc_2202_hmac_md5() ++ [long_hmac(md5)],
- [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(ripemd160 = Type, Config) ->
Msgs = ripemd160_msgs(),
Digests = ripemd160_digests(),
@@ -1705,56 +1750,41 @@ group_config(ripemd160 = Type, Config) ->
group_config(sha = Type, Config) ->
Msgs = [rfc_4634_test1(), rfc_4634_test2_1(),long_msg()],
Digests = rfc_4634_sha_digests() ++ [long_sha_digest()],
- Keys = rfc_2202_sha_keys() ++ [long_hmac_key(sha)],
- Data = rfc_2202_msgs() ++ [long_msg()],
- Hmac = rfc_2202_hmac_sha() ++ [long_hmac(sha)],
- [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+ [{hash, {Type, Msgs, Digests}} | 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];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(sha256 = Type, Config) ->
Msgs = [rfc_4634_test1(), rfc_4634_test2_1(), long_msg()],
Digests = rfc_4634_sha256_digests() ++ [long_sha256_digest()],
- Keys = rfc_4231_keys() ++ [long_hmac_key(sha256)],
- Data = rfc_4231_msgs() ++ [long_msg()],
- Hmac = rfc4231_hmac_sha256() ++ [long_hmac(sha256)],
- [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(sha384 = Type, Config) ->
Msgs = [rfc_4634_test1(), rfc_4634_test2(), long_msg()],
Digests = rfc_4634_sha384_digests() ++ [long_sha384_digest()],
- Keys = rfc_4231_keys() ++ [long_hmac_key(sha384)],
- Data = rfc_4231_msgs() ++ [long_msg()],
- Hmac = rfc4231_hmac_sha384() ++ [long_hmac(sha384)],
- [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(sha512 = Type, Config) ->
Msgs = [rfc_4634_test1(), rfc_4634_test2(), long_msg()],
Digests = rfc_4634_sha512_digests() ++ [long_sha512_digest()],
- Keys = rfc_4231_keys() ++ [long_hmac_key(sha512)],
- Data = rfc_4231_msgs() ++ [long_msg()],
- Hmac = rfc4231_hmac_sha512() ++ [long_hmac(sha512)],
- [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(sha3_224 = Type, Config) ->
{Msgs,Digests} = sha3_test_vectors(Type),
- [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(sha3_256 = Type, Config) ->
{Msgs,Digests} = sha3_test_vectors(Type),
- [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(sha3_384 = Type, Config) ->
{Msgs,Digests} = sha3_test_vectors(Type),
- [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(sha3_512 = Type, Config) ->
{Msgs,Digests} = sha3_test_vectors(Type),
- [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(blake2b = Type, Config) ->
{Msgs, Digests} = blake2_test_vectors(Type),
- [{hash, {Type, Msgs, Digests}}, {hmac, blake2_hmac(Type)} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(blake2s = Type, Config) ->
{Msgs, Digests} = blake2_test_vectors(Type),
- [{hash, {Type, Msgs, Digests}}, {hmac, blake2_hmac(Type)} | Config];
+ [{hash, {Type, Msgs, Digests}} | Config];
group_config(rsa, Config) ->
Msg = rsa_plain(),
Public = rsa_public(),
@@ -1828,7 +1858,6 @@ group_config(Type, Config) when Type == ed25519 ; Type == ed448 ->
group_config(srp, Config) ->
GenerateCompute = [srp3(), srp6(), srp6a(), srp6a_smaller_prime()],
[{generate_compute, GenerateCompute} | Config];
-
group_config(ecdh, Config) ->
Compute = ecdh(),
Generate = ecc(),
@@ -1836,19 +1865,6 @@ group_config(ecdh, Config) ->
group_config(dh, Config) ->
GenerateCompute = [dh()],
[{generate_compute, GenerateCompute} | Config];
-
-group_config(aes_cbc128 = Type, Config) ->
- Block = fun() -> aes_cbc128(Config) end,
- Pairs = fun() -> cmac_nist(Config, Type) end,
- [{cipher, Block}, {cmac, Pairs} | Config];
-group_config(aes_cbc256 = Type, Config) ->
- Block = fun() -> aes_cbc256(Config) end,
- Pairs = fun() -> cmac_nist(Config, Type) end,
- [{cipher, Block}, {cmac, Pairs} | Config];
-group_config(chacha20_poly1305, Config) ->
- AEAD = chacha20_poly1305(Config),
- [{cipher, AEAD} | Config];
-
group_config(poly1305, Config) ->
V = [%% {Key, Txt, Expect}
{%% RFC7539 2.5.2
@@ -1864,6 +1880,76 @@ group_config(F, Config) ->
[{cipher, TestVectors} | Config].
+configure_mac(MacType, SubType, Config) ->
+ case do_configure_mac(MacType, SubType, Config) of
+ undefined ->
+ {skip, io:format("No ~p test vectors for ~p", [MacType, SubType])};
+ Pairs ->
+ [{MacType, Pairs} | Config]
+ end.
+
+do_configure_mac(hmac, Type, _Config) ->
+ case Type of
+ md5 ->
+ Keys = rfc_2202_md5_keys() ++ [long_hmac_key(md5)],
+ Data = rfc_2202_msgs() ++ [long_msg()],
+ Hmac = rfc_2202_hmac_md5() ++ [long_hmac(md5)],
+ zip3_special(hmac, Type, Keys, Data, Hmac);
+ sha ->
+ Keys = rfc_2202_sha_keys() ++ [long_hmac_key(sha)],
+ Data = rfc_2202_msgs() ++ [long_msg()],
+ Hmac = rfc_2202_hmac_sha() ++ [long_hmac(sha)],
+ zip3_special(hmac, Type, Keys, Data, Hmac);
+ sha224 ->
+ Keys = rfc_4231_keys(),
+ Data = rfc_4231_msgs(),
+ Hmac = rfc4231_hmac_sha224(),
+ zip3_special(hmac, Type, Keys, Data, Hmac);
+ sha256 ->
+ Keys = rfc_4231_keys() ++ [long_hmac_key(sha256)],
+ Data = rfc_4231_msgs() ++ [long_msg()],
+ Hmac = rfc4231_hmac_sha256() ++ [long_hmac(sha256)],
+ zip3_special(hmac, Type, Keys, Data, Hmac);
+ sha384 ->
+ Keys = rfc_4231_keys() ++ [long_hmac_key(sha384)],
+ Data = rfc_4231_msgs() ++ [long_msg()],
+ Hmac = rfc4231_hmac_sha384() ++ [long_hmac(sha384)],
+ zip3_special(hmac, Type, Keys, Data, Hmac);
+ sha512 ->
+ Keys = rfc_4231_keys() ++ [long_hmac_key(sha512)],
+ Data = rfc_4231_msgs() ++ [long_msg()],
+ Hmac = rfc4231_hmac_sha512() ++ [long_hmac(sha512)],
+ zip3_special(hmac, Type, Keys, Data, Hmac);
+ sha3_224 ->
+ hmac_sha3(Type);
+ sha3_256 ->
+ hmac_sha3(Type);
+ sha3_384 ->
+ hmac_sha3(Type);
+ sha3_512 ->
+ hmac_sha3(Type);
+ blake2b ->
+ blake2_hmac(Type);
+ blake2s ->
+ blake2_hmac(Type);
+ _ ->
+ undefined
+ end;
+do_configure_mac(cmac, Cipher, Config) ->
+ case Cipher of
+ aes_128_cbc ->
+ fun() -> read_rsp(Config, Cipher, ["CMACGenAES128.rsp", "CMACVerAES128.rsp"]) end;
+ aes_256_cbc ->
+ fun() -> read_rsp(Config, Cipher, ["CMACGenAES256.rsp", "CMACVerAES256.rsp"]) end;
+ _ ->
+ undefined
+ end.
+
+
+zip3_special(Type, SubType, As, Bs, Cs) ->
+ [{Type, SubType, A, B, C}
+ || {A,B,C} <- lists:zip3(As, Bs, Cs)].
+
rsa_sign_verify_tests(Config, Msg, Public, Private, PublicS, PrivateS, OptsToTry) ->
case ?config(fips, Config) of
@@ -1981,10 +2067,8 @@ blake2_test_vectors(blake2s) ->
]}.
blake2_hmac(Type) ->
- {Ks, Ds, Hs} = lists:unzip3(
- [ {hexstr2bin(K), hexstr2bin(D), H}
- || {{K, D}, H} <- lists:zip(blake2_hmac_key_data(), blake2_hmac_hmac(Type)) ]),
- {Type, Ks, Ds, Hs}.
+ [{hmac, Type, hexstr2bin(K), hexstr2bin(D), H}
+ || {{K, D}, H} <- lists:zip(blake2_hmac_key_data(), blake2_hmac_hmac(Type)) ].
blake2_hmac_key_data() ->
[ {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 0b0b0b0b",
@@ -2083,12 +2167,8 @@ hmac_sha3(Type) ->
sha3_384 -> 3;
sha3_512 -> 4
end,
- {Keys, Datas, Hmacs} =
- lists:unzip3(
- [{hexstr2bin(Key), hexstr2bin(Data), hexstr2bin(element(N,Hmacs))}
- || {Key,Data,Hmacs} <- hmac_sha3_data()]),
- {Type, Keys, Datas, Hmacs}.
-
+ [{hmac, Type, hexstr2bin(Key), hexstr2bin(Data), hexstr2bin(element(N,Hmacs))}
+ || {Key,Data,Hmacs} <- hmac_sha3_data()].
hmac_sha3_data() ->
[
@@ -3843,14 +3923,6 @@ ecc() ->
end,
TestCases).
-cmac_nist(Config, aes_cbc128 = Type) ->
- read_rsp(Config, Type,
- ["CMACGenAES128.rsp", "CMACVerAES128.rsp"]);
-
-cmac_nist(Config, aes_cbc256 = Type) ->
- read_rsp(Config, Type,
- ["CMACGenAES256.rsp", "CMACVerAES256.rsp"]).
-
int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
int_to_bin(X) -> int_to_bin_pos(X, []).
@@ -4068,12 +4140,11 @@ parse_rsp_cmac(Type, Key0, Msg0, Mlen0, Tlen, MAC0, Next, State, Acc) ->
Mlen = binary_to_integer(Mlen0),
<<Msg:Mlen/bytes, _/binary>> = hexstr2bin(Msg0),
MAC = hexstr2bin(MAC0),
-
case binary_to_integer(Tlen) of
0 ->
- parse_rsp(Type, Next, State, [{Type, Key, Msg, MAC}|Acc]);
+ parse_rsp(Type, Next, State, [{cmac, Type, Key, Msg, MAC}|Acc]);
I ->
- parse_rsp(Type, Next, State, [{Type, Key, Msg, I, MAC}|Acc])
+ parse_rsp(Type, Next, State, [{cmac, Type, Key, Msg, I, MAC}|Acc])
end.
api_errors_ecdh(Config) when is_list(Config) ->
diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index 443de7b0dd..8dd814982d 100644
--- a/lib/dialyzer/doc/src/dialyzer.xml
+++ b/lib/dialyzer/doc/src/dialyzer.xml
@@ -537,7 +537,10 @@ Option :: {files, [Filename :: string()]}
'plt_check' |
'plt_remove'}
| {warnings, [WarnOpts]}
- | {get_warnings, bool()}
+ | {get_warnings, boolean()}
+ | {native, boolean()}
+ %% Defaults to false when invoked from Erlang
+ | {native_cache, boolean()}
WarnOpts :: error_handling
| no_behaviours
diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl
index 4a12b9b671..e1821f10eb 100644
--- a/lib/dialyzer/src/dialyzer.hrl
+++ b/lib/dialyzer/src/dialyzer.hrl
@@ -160,7 +160,9 @@
indent_opt = ?INDENT_OPT :: iopt(),
callgraph_file = "" :: file:filename(),
check_plt = true :: boolean(),
- solvers = [] :: [solver()]}).
+ solvers = [] :: [solver()],
+ native = maybe :: boolean() | 'maybe',
+ native_cache = true :: boolean()}).
-record(contract, {contracts = [] :: [contract_pair()],
args = [] :: [erl_types:erl_type()],
diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl
index f887f661bd..403fcb6279 100644
--- a/lib/dialyzer/src/dialyzer_cl.erl
+++ b/lib/dialyzer/src/dialyzer_cl.erl
@@ -489,10 +489,20 @@ expand_dependent_modules_1([], Included, _ModDeps) ->
-spec hipe_compile([file:filename()], #options{}) -> 'ok'.
-hipe_compile(Files, #options{erlang_mode = ErlangMode} = Options) ->
- NoNative = (get(dialyzer_options_native) =:= false),
+hipe_compile(Files, #options{erlang_mode = ErlangMode,
+ native = Native,
+ native_cache = NativeCache} = Options) ->
+ NoNative =
+ case ErlangMode of
+ true ->
+ %% In Erlang mode, native compilation must be explicitly enabled
+ Native =/= true;
+ false ->
+ %% In CLI mode, perform native compilation unless disabled
+ Native =:= false
+ end,
FewFiles = (length(Files) < ?MIN_FILES_FOR_NATIVE_COMPILE),
- case NoNative orelse FewFiles orelse ErlangMode of
+ case NoNative orelse FewFiles of
true -> ok;
false ->
case erlang:system_info(hipe_architecture) of
@@ -508,8 +518,7 @@ hipe_compile(Files, #options{erlang_mode = ErlangMode} = Options) ->
dialyzer_worker],
report_native_comp(Options),
{T1, _} = statistics(wall_clock),
- Cache = (get(dialyzer_options_native_cache) =/= false),
- native_compile(Mods, Cache),
+ native_compile(Mods, NativeCache),
{T2, _} = statistics(wall_clock),
report_elapsed_time(T1, T2, Options)
end
diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl
index 280cae81d5..cadc2116b0 100644
--- a/lib/dialyzer/src/dialyzer_cl_parse.erl
+++ b/lib/dialyzer/src/dialyzer_cl_parse.erl
@@ -316,7 +316,9 @@ common_options() ->
{use_spec, get(dialyzer_options_use_contracts)},
{warnings, get(dialyzer_warnings)},
{check_plt, get(dialyzer_options_check_plt)},
- {solvers, get(dialyzer_solvers)}].
+ {solvers, get(dialyzer_solvers)},
+ {native, get(dialyzer_options_native)},
+ {native_cache, get(dialyzer_options_native_cache)}].
%%-----------------------------------------------------------------------
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index 3b30036c1c..f88f4f8ea2 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -197,6 +197,10 @@ build_options([{OptionName, Value} = Term|Rest], Options) ->
solvers ->
assert_solvers(Value),
build_options(Rest, Options#options{solvers = Value});
+ native ->
+ build_options(Rest, Options#options{native = Value});
+ native_cache ->
+ build_options(Rest, Options#options{native_cache = Value});
_ ->
bad_option("Unknown dialyzer command line option", Term)
end;
diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl
index 9d7538a13d..f3e24263b8 100644
--- a/lib/inets/src/http_server/httpd_request.erl
+++ b/lib/inets/src/http_server/httpd_request.erl
@@ -196,9 +196,9 @@ parse_headers(<<?CR,?LF,?LF,Body/binary>>, [], [], Current, Max, Options, Result
parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], Current, Max,
Options, Result);
-parse_headers(<<?LF,?LF,Body/binary>>, [], [], Current, Max, Options, Result) ->
+parse_headers(<<?LF,?LF,Body/binary>>, Header, Headers, Current, Max, Options, Result) ->
%% If ?CR is is missing RFC2616 section-19.3
- parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], Current, Max,
+ parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, Header, Headers, Current, Max,
Options, Result);
parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], _, _, _, Result) ->
diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl
index 0a5aed67d5..3ff3ed4e97 100644
--- a/lib/inets/test/http_format_SUITE.erl
+++ b/lib/inets/test/http_format_SUITE.erl
@@ -414,6 +414,19 @@ http_request(Config) when is_list(Config) ->
{max_content_length, ?HTTP_MAX_CONTENT_LENGTH}
]], HttpHead2),
+ %% If ?CR is is missing RFC2616 section-19.3
+ HttpHead3 = ["GET http://www.erlang.org HTTP/1.1", [?LF],
+ "Accept: text/html", [?LF, ?LF]],
+ {"GET",
+ "http://www.erlang.org",
+ "HTTP/1.1",
+ {#http_request_h{}, [{"accept","text/html"}]}, <<>>} =
+ parse(httpd_request, parse, [[{max_header, ?HTTP_MAX_HEADER_SIZE},
+ {max_version, ?HTTP_MAX_VERSION_STRING},
+ {max_method, ?HTTP_MAX_METHOD_STRING},
+ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH}
+ ]], HttpHead3),
+
%% Note the following body is not related to the headers above
HttpBody = ["<HTML>\n<HEAD>\n<TITLE> dummy </TITLE>\n</HEAD>\n<BODY>\n",
"<H1>dummy</H1>\n</BODY>\n</HTML>\n"],
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index d20fc1fdfd..6c0d072fed 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -213,12 +213,93 @@
</func>
<func>
- <name name="send" arity="4" since=""/>
+ <name name="send" arity="3" since="OTP @OTP-15747@"/>
<fsummary>Send a packet.</fsummary>
<desc>
<p>
- Sends a packet to the specified address and port. Argument
- <c><anno>Address</anno></c> can be a hostname or a socket address.
+ Sends a packet to the specified <c><anno>Destination</anno></c>.
+ </p>
+ <p>
+ This function is equivalent to
+ <seealso marker="#send-4-AncData"><c>send(<anno>Socket</anno>, <anno>Destination</anno>, [], <anno>Packet</anno>)</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="4" clause_i="1" since=""/>
+ <fsummary>Send a packet.</fsummary>
+ <desc>
+ <p>
+ Sends a packet to the specified <c><anno>Host</anno></c>
+ and <c><anno>Port</anno></c>.
+ </p>
+ <p>
+ This clause is equivalent to
+ <seealso marker="#send/5"><c>send(<anno>Socket</anno>, <anno>Host</anno>, <anno>Port</anno>, [], <anno>Packet</anno>)</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="4" clause_i="2" anchor="send-4-AncData" since="OTP @OTP-15747@"/>
+ <fsummary>Send a packet.</fsummary>
+ <desc>
+ <p>
+ Sends a packet to the specified <c><anno>Destination</anno></c>
+ with ancillary data <c><anno>AncData</anno></c>.
+ </p>
+ <note>
+ <p>
+ The ancillary data <c><anno>AncData</anno></c>
+ contains options that for this single message
+ override the default options for the socket,
+ an operation that may not be supported on all platforms,
+ and if so return <c>{error, einval}</c>.
+ Using more than one of an ancillary data item type
+ may also not be supported.
+ <c><anno>AncData</anno> =:= []</c> is always supported.
+ </p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="4" clause_i="3" since="OTP @OTP-15747@"/>
+ <fsummary>Send a packet.</fsummary>
+ <desc>
+ <p>
+ Sends a packet to the specified <c><anno>Destination</anno></c>.
+ Since <c><anno>Destination</anno></c> is complete,
+ <c><anno>PortZero</anno></c> is redundant and has to be <c>0</c>.
+ </p>
+ <p>
+ This is a legacy clause mostly for
+ <c><anno>Destination</anno> = {local, Binary}</c>
+ where <c><anno>PortZero</anno></c> is superfluous.
+ It is equivalent to
+ <seealso marker="#send-4-AncData"><c>send(<anno>Socket</anno>, <anno>Destination</anno>, [], <anno>Packet</anno>)</c></seealso>, the clause right above here.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="5" since="OTP @OTP-15747@"/>
+ <fsummary>Send a packet.</fsummary>
+ <desc>
+ <p>
+ Sends a packet to the specified <c><anno>Host</anno></c>
+ and <c><anno>Port</anno></c>,
+ with ancillary data <c><anno>AncData</anno></c>.
+ </p>
+ <p>
+ Argument <c><anno>Host</anno></c> can be
+ a hostname or a socket address,
+ and <c><anno>Port</anno></c> can be a port number
+ or a service name atom.
+ These are resolved into a <c>Destination</c> and after that
+ this function is equivalent to
+ <seealso marker="#send-4-AncData"><c>send(<anno>Socket</anno>, Destination, <anno>AncData</anno>, <anno>Packet</anno>)</c></seealso>, read there about ancillary data.
</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index d4678ca5db..1011befca0 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -118,6 +118,42 @@ fe80::204:acff:fe17:bf38
<name name="port_number"/>
</datatype>
<datatype>
+ <name name="family_address" since="OTP @OTP-15747@"/>
+ <desc>
+ <p>
+ A general address format on the form <c>{Family, Destination}</c>
+ where <c>Family</c> is an atom such as <c>local</c>
+ and the format of <c>Destination</c> depends on <c>Family</c>,
+ and is a complete address
+ (for example an IP address including port number).
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="inet_address" since="OTP @OTP-15747@"/>
+ <desc>
+ <warning>
+ <p>
+ This address format is for now experimental
+ and for completeness to make all address families have a
+ <c>{Family, Destination}</c> representation.
+ </p>
+ </warning>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="inet6_address" since="OTP @OTP-15747@"/>
+ <desc>
+ <warning>
+ <p>
+ This address format is for now experimental
+ and for completeness to make all address families have a
+ <c>{Family, Destination}</c> representation.
+ </p>
+ </warning>
+ </desc>
+ </datatype>
+ <datatype>
<name name="local_address"/>
<desc>
<p>
@@ -180,12 +216,16 @@ fe80::204:acff:fe17:bf38
<name name="ancillary_data"/>
<desc>
<p>
- Ancillary data received with the data packet
- or read with the socket option
+ Ancillary data received with the data packet,
+ read with the socket option
<seealso marker="gen_tcp#type-pktoptions_value">
<c>pktoptions</c>
</seealso>
- from a TCP socket.
+ from a TCP socket,
+ or to set in a call to
+ <seealso marker="gen_udp#send-4-AncData"><c>gen_udp:send/4</c></seealso>
+ or
+ <seealso marker="gen_udp#send/5"><c>gen_udp:send/5</c></seealso>.
</p>
<p>
The value(s) correspond to the currently active socket
@@ -193,7 +233,9 @@ fe80::204:acff:fe17:bf38
<seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
<seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
and
- <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>.
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>,
+ or for a single send operation the option(s) to override
+ the currently active socket option(s).
</p>
</desc>
</datatype>
diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl
index e6a30d0b92..42261d371d 100644
--- a/lib/kernel/src/erts_debug.erl
+++ b/lib/kernel/src/erts_debug.erl
@@ -92,7 +92,7 @@ copy_shared(_) ->
-spec get_internal_state(W) -> term() when
W :: reds_left | node_and_dist_references | monitoring_nodes
- | next_pid | 'DbTable_words' | check_io_debug
+ | next_pid | 'DbTable_words' | check_io_debug | lc_graph
| process_info_args | processes | processes_bif_info
| max_atom_out_cache_index | nbalance | available_internal_state
| force_heap_frags | memory
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index fad7b2f887..3001948209 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -20,7 +20,7 @@
-module(gen_udp).
-export([open/1, open/2, close/1]).
--export([send/2, send/4, recv/2, recv/3, connect/3]).
+-export([send/2, send/3, send/4, send/5, recv/2, recv/3, connect/3]).
-export([controlling_process/2]).
-export([fdopen/2]).
@@ -125,20 +125,80 @@ open(Port, Opts0) ->
close(S) ->
inet:udp_close(S).
--spec send(Socket, Address, Port, Packet) -> ok | {error, Reason} when
+-spec send(Socket, Destination, Packet) -> ok | {error, Reason} when
Socket :: socket(),
- Address :: inet:socket_address() | inet:hostname(),
- Port :: inet:port_number(),
+ Destination :: {inet:ip_address(), inet:port_number()} |
+ inet:family_address(),
+ Packet :: iodata(),
+ Reason :: not_owner | inet:posix().
+%%%
+send(Socket, Destination, Packet) ->
+ send(Socket, Destination, [], Packet).
+
+-spec send(Socket, Host, Port, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Host :: inet:hostname() | inet:ip_address(),
+ Port :: inet:port_number() | atom(),
+ Packet :: iodata(),
+ Reason :: not_owner | inet:posix();
+%%%
+ (Socket, Destination, AncData, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Destination :: {inet:ip_address(), inet:port_number()} |
+ inet:family_address(),
+ AncData :: inet:ancillary_data(),
+ Packet :: iodata(),
+ Reason :: not_owner | inet:posix();
+%%%
+ (Socket, Destination, PortZero, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Destination :: {inet:ip_address(), inet:port_number()} |
+ inet:family_address(),
+ PortZero :: inet:port_number(),
Packet :: iodata(),
Reason :: not_owner | inet:posix().
+%%%
+send(S, {_,_} = Destination, PortZero = AncData, Packet) when is_port(S) ->
+ %% Destination is {Family,Addr} | {IP,Port},
+ %% so it is complete - argument PortZero is redundant
+ if
+ PortZero =:= 0 ->
+ case inet_db:lookup_socket(S) of
+ {ok, Mod} ->
+ Mod:send(S, Destination, [], Packet);
+ Error ->
+ Error
+ end;
+ is_integer(PortZero) ->
+ %% Redundant PortZero; must be 0
+ {error, einval};
+ is_list(AncData) ->
+ case inet_db:lookup_socket(S) of
+ {ok, Mod} ->
+ Mod:send(S, Destination, AncData, Packet);
+ Error ->
+ Error
+ end
+ end;
+send(S, Host, Port, Packet) when is_port(S) ->
+ send(S, Host, Port, [], Packet).
-send(S, Address, Port, Packet) when is_port(S) ->
+-spec send(Socket, Host, Port, AncData, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Host :: inet:hostname() | inet:ip_address() | inet:local_address(),
+ Port :: inet:port_number() | atom(),
+ AncData :: inet:ancillary_data(),
+ Packet :: iodata(),
+ Reason :: not_owner | inet:posix().
+%%%
+send(S, Host, Port, AncData, Packet)
+ when is_port(S), is_list(AncData) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
- case Mod:getaddr(Address) of
+ case Mod:getaddr(Host) of
{ok,IP} ->
case Mod:getserv(Port) of
- {ok,UP} -> Mod:send(S, IP, UP, Packet);
+ {ok,P} -> Mod:send(S, {IP,P}, AncData, Packet);
{error,einval} -> exit(badarg);
Error -> Error
end;
@@ -149,6 +209,7 @@ send(S, Address, Port, Packet) when is_port(S) ->
Error
end.
+%% Connected send
send(S, Packet) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 9f22eb6aaa..7940903658 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -75,7 +75,8 @@
-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0,
ip6_address/0, ip_address/0, port_number/0,
- local_address/0, socket_address/0, returned_non_ip_address/0,
+ family_address/0, local_address/0,
+ socket_address/0, returned_non_ip_address/0,
socket_setopt/0, socket_getopt/0, ancillary_data/0,
posix/0, socket/0, stat_option/0]).
%% imports
@@ -100,11 +101,16 @@
0..65535,0..65535,0..65535,0..65535}.
-type ip_address() :: ip4_address() | ip6_address().
-type port_number() :: 0..65535.
--type local_address() :: {local, File :: binary() | string()}.
+-type family_address() :: inet_address() | inet6_address() | local_address().
+-type inet_address() ::
+ {'inet', {ip4_address() | 'any' | 'loopback', port_number()}}.
+-type inet6_address() ::
+ {'inet6', {ip6_address() | 'any' | 'loopback', port_number()}}.
+-type local_address() :: {'local', File :: binary() | string()}.
-type returned_non_ip_address() ::
- {local, binary()} |
- {unspec, <<>>} |
- {undefined, any()}.
+ {'local', binary()} |
+ {'unspec', <<>>} |
+ {'undefined', any()}.
-type posix() ::
'eaddrinuse' | 'eaddrnotavail' | 'eafnosupport' | 'ealready' |
'econnaborted' | 'econnrefused' | 'econnreset' |
diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl
index 71db0357cd..cb95a69798 100644
--- a/lib/kernel/src/inet6_udp.erl
+++ b/lib/kernel/src/inet6_udp.erl
@@ -65,16 +65,25 @@ open(Port, Opts) ->
{ok, _} -> exit(badarg)
end.
-send(S, Addr = {A,B,C,D,E,F,G,H}, P, Data)
- when ?ip6(A,B,C,D,E,F,G,H), ?port(P) ->
- prim_inet:sendto(S, Addr, P, Data).
+send(S, {A,B,C,D,E,F,G,H} = IP, Port, Data)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
+ prim_inet:sendto(S, {IP, Port}, [], Data);
+send(S, {{A,B,C,D,E,F,G,H}, Port} = Addr, AncData, Data)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Addr, AncData, Data);
+send(S, {?FAMILY, {{A,B,C,D,E,F,G,H}, Port}} = Address, AncData, Data)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Address, AncData, Data);
+send(S, {?FAMILY, {loopback, Port}} = Address, AncData, Data)
+ when ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Address, AncData, Data).
send(S, Data) ->
- prim_inet:sendto(S, {0,0,0,0,0,0,0,0}, 0, Data).
+ prim_inet:sendto(S, {any, 0}, [], Data).
-connect(S, Addr = {A,B,C,D,E,F,G,H}, P)
- when ?ip6(A,B,C,D,E,F,G,H), ?port(P) ->
- prim_inet:connect(S, Addr, P).
+connect(S, Addr = {A,B,C,D,E,F,G,H}, Port)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
+ prim_inet:connect(S, Addr, Port).
recv(S, Len) ->
prim_inet:recvfrom(S, Len).
diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl
index 1e624b9e90..083059a2dc 100644
--- a/lib/kernel/src/inet_udp.erl
+++ b/lib/kernel/src/inet_udp.erl
@@ -66,16 +66,25 @@ open(Port, Opts) ->
{ok, _} -> exit(badarg)
end.
-send(S, {A,B,C,D} = Addr, P, Data)
- when ?ip(A,B,C,D), ?port(P) ->
- prim_inet:sendto(S, Addr, P, Data).
+send(S, {A,B,C,D} = IP, Port, Data)
+ when ?ip(A,B,C,D), ?port(Port) ->
+ prim_inet:sendto(S, {IP, Port}, [], Data);
+send(S, {{A,B,C,D}, Port} = Addr, AncData, Data)
+ when ?ip(A,B,C,D), ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Addr, AncData, Data);
+send(S, {?FAMILY, {{A,B,C,D}, Port}} = Address, AncData, Data)
+ when ?ip(A,B,C,D), ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Address, AncData, Data);
+send(S, {?FAMILY, {loopback, Port}} = Address, AncData, Data)
+ when ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Address, AncData, Data).
send(S, Data) ->
- prim_inet:sendto(S, {0,0,0,0}, 0, Data).
+ prim_inet:sendto(S, {any, 0}, [], Data).
-connect(S, Addr = {A,B,C,D}, P)
- when ?ip(A,B,C,D), ?port(P) ->
- prim_inet:connect(S, Addr, P).
+connect(S, Addr = {A,B,C,D}, Port)
+ when ?ip(A,B,C,D), ?port(Port) ->
+ prim_inet:connect(S, Addr, Port).
recv(S, Len) ->
prim_inet:recvfrom(S, Len).
diff --git a/lib/kernel/src/local_udp.erl b/lib/kernel/src/local_udp.erl
index 481a8c4910..933e56228b 100644
--- a/lib/kernel/src/local_udp.erl
+++ b/lib/kernel/src/local_udp.erl
@@ -70,11 +70,13 @@ open(0, Opts) ->
{ok, _} -> exit(badarg)
end.
-send(S, Addr = {?FAMILY,_}, 0, Data) ->
- prim_inet:sendto(S, Addr, 0, Data).
+send(S, {?FAMILY,_} = Addr, 0, Data) ->
+ prim_inet:sendto(S, Addr, [], Data);
+send(S, {?FAMILY,_} = Addr, AncData, Data) when is_list(AncData) ->
+ prim_inet:sendto(S, Addr, AncData, Data).
%%
send(S, Data) ->
- prim_inet:sendto(S, {?FAMILY,<<>>}, 0, Data).
+ prim_inet:sendto(S, {?FAMILY,<<>>}, [], Data).
connect(S, Addr = {?FAMILY,_}, 0) ->
prim_inet:connect(S, Addr, 0).
diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl
index 0c9e1ea303..5a3487a9ba 100644
--- a/lib/kernel/src/user.erl
+++ b/lib/kernel/src/user.erl
@@ -296,7 +296,8 @@ io_requests([], Stat, _) ->
%% port.
put_port(List, Port) ->
- send_port(Port, {command, List}).
+ true = port_command(Port, List),
+ ok.
%% send_port(Port, Command)
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index 69ff8e7971..644aa752b6 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -543,19 +543,14 @@ set_unicode_state(Iport, Bool) ->
%% io_request(Request, InPort, OutPort)
%% io_requests(Requests, InPort, OutPort)
%% Note: InPort is unused.
-
-io_request(Request, Iport, Oport) ->
- try io_command(Request) of
- {command,_} = Command ->
- Oport ! {self(),Command},
- ok;
- {Command,Reply} ->
- Oport ! {self(),Command},
- Reply
- catch
- {requests,Rs} ->
- io_requests(Rs, Iport, Oport);
- _ ->
+io_request({requests,Rs}, Iport, Oport) ->
+ io_requests(Rs, Iport, Oport);
+io_request(Request, _Iport, Oport) ->
+ case io_command(Request) of
+ {Data, Reply} ->
+ true = port_command(Oport, Data),
+ Reply;
+ unhandled ->
ok
end.
@@ -575,19 +570,19 @@ put_int16(N, Tail) ->
%% to the console before the vm stops when calling erlang:halt(integer()).
-dialyzer({no_improper_lists, io_command/1}).
io_command({put_chars_sync, unicode,Cs,Reply}) ->
- {{command,[?OP_PUTC_SYNC|unicode:characters_to_binary(Cs,utf8)]},Reply};
+ {[?OP_PUTC_SYNC|unicode:characters_to_binary(Cs,utf8)], Reply};
io_command({put_chars, unicode,Cs}) ->
- {command,[?OP_PUTC|unicode:characters_to_binary(Cs,utf8)]};
+ {[?OP_PUTC|unicode:characters_to_binary(Cs,utf8)], ok};
io_command({move_rel,N}) ->
- {command,[?OP_MOVE|put_int16(N, [])]};
+ {[?OP_MOVE|put_int16(N, [])], ok};
io_command({insert_chars,unicode,Cs}) ->
- {command,[?OP_INSC|unicode:characters_to_binary(Cs,utf8)]};
+ {[?OP_INSC|unicode:characters_to_binary(Cs,utf8)], ok};
io_command({delete_chars,N}) ->
- {command,[?OP_DELC|put_int16(N, [])]};
+ {[?OP_DELC|put_int16(N, [])], ok};
io_command(beep) ->
- {command,[?OP_BEEP]};
-io_command(Else) ->
- throw(Else).
+ {[?OP_BEEP], ok};
+io_command(_) ->
+ unhandled.
%% gr_new()
%% gr_get_num(Group, Index)
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index c91808d4ae..8d25ac5dde 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -2021,7 +2021,7 @@ recvtclass(_Config) ->
recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
%% Using the option returns einval, so it is not implemented.
-recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
%% Does not return any value - not implemented for pktoptions
recvtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
@@ -2033,7 +2033,7 @@ recvtos_ok(_, _) -> false.
recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
%% Using the option returns einval, so it is not implemented.
-recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
%% Does not return any value - not implemented for pktoptions
recvttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,7,0});
@@ -2046,7 +2046,7 @@ recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
%% Using the option returns einval, so it is not implemented.
-recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
%% Does not return any value - not implemented for pktoptions
recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
%%
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index af9985de45..730886865c 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -37,6 +37,7 @@
buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1,
read_packets/1, open_fd/1, connect/1, implicit_inet6/1,
recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1,
+ sendtos/1, sendtosttl/1, sendttl/1, sendtclass/1,
local_basic/1, local_unbound/1,
local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]).
@@ -49,6 +50,7 @@ all() ->
bad_address, read_packets, open_fd, connect,
implicit_inet6, active_n,
recvtos, recvtosttl, recvttl, recvtclass,
+ sendtos, sendtosttl, sendttl, sendtclass,
{group, local}].
groups() ->
@@ -312,7 +314,6 @@ read_packets(Config) when is_list(Config) ->
{ok,R} = gen_udp:open(0, [{read_packets,N1}]),
{ok,RP} = inet:port(R),
{ok,Node} = start_node(gen_udp_SUITE_read_packets),
- Die = make_ref(),
%%
{V1, Trace1} = read_packets_test(R, RP, Msgs, Node),
{ok,[{read_packets,N1}]} = inet:getopts(R, [read_packets]),
@@ -324,7 +325,7 @@ read_packets(Config) when is_list(Config) ->
stop_node(Node),
ct:log("N1=~p, V1=~p vs N2=~p, V2=~p",[N1,V1,N2,V2]),
- dump_terms(Config, "trace1.terms", Trace2),
+ dump_terms(Config, "trace1.terms", Trace1),
dump_terms(Config, "trace2.terms", Trace2),
%% Because of the inherit racy-ness of the feature it is
@@ -348,15 +349,6 @@ dump_terms(Config, Name, Terms) ->
file:write_file(FName, term_to_binary(Terms)),
ct:log("Logged terms to ~s",[FName]).
-infinite_loop(Die) ->
- receive
- Die ->
- ok
- after
- 0 ->
- infinite_loop(Die)
- end.
-
read_packets_test(R, RP, Msgs, Node) ->
Receiver = self(),
Tracer =
@@ -577,19 +569,19 @@ active_n(Config) when is_list(Config) ->
recvtos(_Config) ->
test_recv_opts(
- inet, [{recvtos,tos,96}],
+ inet, [{recvtos,tos,96}], false,
fun recvtos_ok/2).
recvtosttl(_Config) ->
test_recv_opts(
- inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}], false,
fun (OSType, OSVer) ->
recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
end).
recvttl(_Config) ->
test_recv_opts(
- inet, [{recvttl,ttl,33}],
+ inet, [{recvttl,ttl,33}], false,
fun recvttl_ok/2).
recvtclass(_Config) ->
@@ -601,15 +593,48 @@ recvtclass(_Config) ->
of
[_] ->
test_recv_opts(
- inet6, [{recvtclass,tclass,224}],
+ inet6, [{recvtclass,tclass,224}], false,
fun recvtclass_ok/2);
[] ->
{skip,ipv6_not_supported,IFs}
end.
+
+sendtos(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96}], true,
+ fun sendtos_ok/2).
+
+sendtosttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}], true,
+ fun (OSType, OSVer) ->
+ sendtos_ok(OSType, OSVer) andalso sendttl_ok(OSType, OSVer)
+ end).
+
+sendttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvttl,ttl,33}], true,
+ fun sendttl_ok/2).
+
+sendtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_recv_opts(
+ inet6, [{recvtclass,tclass,224}], true,
+ fun sendtclass_ok/2);
+ [] ->
+ {skip,ipv6_not_supported,IFs}
+ end.
+
%% These version numbers are just above the highest noted in daily tests
%% where the test fails for a plausible reason, that is the lowest
-%% where we can expect that the test mighe succeed, so
+%% where we can expect that the test might succeed, so
%% skip on platforms lower than this.
%%
%% On newer versions it might be fixed, but we'll see about that
@@ -628,16 +653,55 @@ recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
recvtos_ok({unix,_}, _) -> true;
recvtos_ok(_, _) -> false.
+%% Option has no effect
+recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%%
recvttl_ok({unix,_}, _) -> true;
recvttl_ok(_, _) -> false.
%% Using the option returns einval, so it is not implemented.
recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0});
recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11});
+%% Option has no effect
+recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
%%
recvtclass_ok({unix,_}, _) -> true;
recvtclass_ok(_, _) -> false.
+
+%% To send ancillary data seems to require much higher version numbers
+%% than receiving it...
+%%
+
+%% Using the option returns einval, so it is not implemented.
+sendtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
+sendtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,5,0});
+sendtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+sendtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {4,0,0});
+sendtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
+%%
+sendtos_ok({unix,_}, _) -> true;
+sendtos_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+sendttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
+sendttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {4,0,0});
+%% Using the option returns enoprotoopt, so it is not implemented.
+sendttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
+%% Option has no effect
+sendttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,5,0});
+%%
+sendttl_ok({unix,_}, _) -> true;
+sendttl_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+sendtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0});
+sendtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11});
+%%
+sendtclass_ok({unix,_}, _) -> true;
+sendtclass_ok(_, _) -> false.
+
+
semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
if
X1 > X2 -> false;
@@ -650,18 +714,18 @@ semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
end;
semver_lt(_, {_,_,_}) -> false.
-test_recv_opts(Family, Spec, OSFilter) ->
+test_recv_opts(Family, Spec, TestSend, OSFilter) ->
OSType = os:type(),
OSVer = os:version(),
case OSFilter(OSType, OSVer) of
true ->
io:format("Os: ~p, ~p~n", [OSType,OSVer]),
- test_recv_opts(Family, Spec, OSType, OSVer);
+ test_recv_opts(Family, Spec, TestSend, OSType, OSVer);
false ->
{skip,{not_supported_for_os_version,{OSType,OSVer}}}
end.
%%
-test_recv_opts(Family, Spec, _OSType, _OSVer) ->
+test_recv_opts(Family, Spec, TestSend, _OSType, _OSVer) ->
Timeout = 5000,
RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
@@ -686,16 +750,33 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) ->
ok = inet:setopts(S1, TrueRecvOpts_OptsVals),
{ok,TrueRecvOpts_OptsVals} = inet:getopts(S1, RecvOpts ++ Opts),
%%
+ %% S1 now has true receive options and set option values
+ %%
{ok,S2} =
gen_udp:open(0, [Family,binary,{active,true}|FalseRecvOpts]),
{ok,P2} = inet:port(S2),
{ok,FalseRecvOpts_OptsVals2} = inet:getopts(S2, RecvOpts ++ Opts),
OptsVals2 = FalseRecvOpts_OptsVals2 -- FalseRecvOpts,
%%
- ok = gen_udp:send(S2, Addr, P1, <<"abcde">>),
+ %% S2 now has false receive options and default option values,
+ %% OptsVals2 contains the default option values
+ %%
+ ok = gen_udp:send(S2, {Addr,P1}, <<"abcde">>),
ok = gen_udp:send(S1, Addr, P2, <<"fghij">>),
+ TestSend andalso
+ begin
+ ok = gen_udp:send(S2, Addr, P1, OptsVals, <<"ABCDE">>),
+ ok = gen_udp:send(S2, {Addr,P1}, OptsVals, <<"12345">>)
+ end,
{ok,{_,P2,OptsVals3,<<"abcde">>}} = gen_udp:recv(S1, 0, Timeout),
verify_sets_eq(OptsVals3, OptsVals2),
+ TestSend andalso
+ begin
+ {ok,{_,P2,OptsVals0,<<"ABCDE">>}} = gen_udp:recv(S1, 0, Timeout),
+ {ok,{_,P2,OptsVals1,<<"12345">>}} = gen_udp:recv(S1, 0, Timeout),
+ verify_sets_eq(OptsVals0, OptsVals),
+ verify_sets_eq(OptsVals1, OptsVals)
+ end,
receive
{udp,S2,_,P1,<<"fghij">>} ->
ok;
@@ -710,8 +791,16 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) ->
ok = inet:setopts(S2, TrueRecvOpts),
{ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
%%
- ok = gen_udp:send(S2, Addr, P1, <<"klmno">>),
- ok = gen_udp:send(S1, Addr, P2, <<"pqrst">>),
+ %% S1 now has false receive options and set option values
+ %%
+ %% S2 now has true receive options and default option values
+ %%
+ ok = gen_udp:send(S2, {Addr,P1}, [], <<"klmno">>),
+ ok = gen_udp:send(S1, {Family,{loopback,P2}}, <<"pqrst">>),
+ TestSend andalso
+ begin
+ ok = gen_udp:send(S1, {Family,{loopback,P2}}, OptsVals2, <<"PQRST">>)
+ end,
{ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout),
receive
{udp,S2,_,P1,OptsVals4,<<"pqrst">>} ->
@@ -721,9 +810,18 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) ->
after Timeout ->
exit(timeout)
end,
+ TestSend andalso
+ receive
+ {udp,S2,_,P1,OptsVals5,<<"PQRST">>} ->
+ verify_sets_eq(OptsVals5, OptsVals2);
+ Other3 ->
+ exit({unexpected,Other3})
+ after Timeout ->
+ exit(timeout)
+ end,
ok = gen_udp:close(S1),
ok = gen_udp:close(S2),
-%% exit({{OSType,OSVer},success}), % In search for the truth
+%%% exit({{_OSType,_OSVer},success}), % In search for the truth
ok.
verify_sets_eq(L1, L2) ->
@@ -877,6 +975,10 @@ connect(Config) when is_list(Config) ->
implicit_inet6(Config) when is_list(Config) ->
Host = ok(inet:gethostname()),
case inet:getaddr(Host, inet6) of
+ {ok,{16#fe80,0,0,0,_,_,_,_} = Addr} ->
+ {skip,
+ "Got link local IPv6 address: "
+ ++inet:ntoa(Addr)};
{ok,Addr} ->
implicit_inet6(Host, Addr);
{error,Reason} ->
@@ -927,11 +1029,12 @@ ok({ok,V}) -> V;
ok(NotOk) ->
try throw(not_ok)
catch
- throw:Thrown:Stacktrace ->
- erlang:raise(
- error, {Thrown, NotOk}, tl(Stacktrace))
+ throw:not_ok:Stacktrace ->
+ raise_error({not_ok, NotOk}, tl(Stacktrace))
end.
+raise_error(Reason, Stacktrace) ->
+ erlang:raise(error, Reason, Stacktrace).
local_filename(Tag) ->
"/tmp/" ?MODULE_STRING "_" ++ os:getpid() ++ "_" ++ atom_to_list(Tag).
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 21db887bb5..4da50d2af8 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -923,6 +923,12 @@ signature_scheme(rsa_pss_pss_sha384) -> ?RSA_PSS_PSS_SHA384;
signature_scheme(rsa_pss_pss_sha512) -> ?RSA_PSS_PSS_SHA512;
signature_scheme(rsa_pkcs1_sha1) -> ?RSA_PKCS1_SHA1;
signature_scheme(ecdsa_sha1) -> ?ECDSA_SHA1;
+%% Handling legacy signature algorithms
+signature_scheme({Hash0, Sign0}) ->
+ Hash = hash_algorithm(Hash0),
+ Sign = sign_algorithm(Sign0),
+ <<?UINT16(SigAlg)>> = <<?BYTE(Hash),?BYTE(Sign)>>,
+ SigAlg;
signature_scheme(?RSA_PKCS1_SHA256) -> rsa_pkcs1_sha256;
signature_scheme(?RSA_PKCS1_SHA384) -> rsa_pkcs1_sha384;
signature_scheme(?RSA_PKCS1_SHA512) -> rsa_pkcs1_sha512;
@@ -962,7 +968,9 @@ scheme_to_components(rsa_pss_pss_sha256) -> {sha256, rsa_pss_pss, undefined};
scheme_to_components(rsa_pss_pss_sha384) -> {sha384, rsa_pss_pss, undefined};
scheme_to_components(rsa_pss_pss_sha512) -> {sha512, rsa_pss_pss, undefined};
scheme_to_components(rsa_pkcs1_sha1) -> {sha1, rsa_pkcs1, undefined};
-scheme_to_components(ecdsa_sha1) -> {sha1, ecdsa, undefined}.
+scheme_to_components(ecdsa_sha1) -> {sha1, ecdsa, undefined};
+%% Handling legacy signature algorithms
+scheme_to_components({Hash,Sign}) -> {Hash, Sign, undefined}.
%% TODO: Add support for EC and RSA-SSA signatures
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 1f0c95701b..bd9407a207 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1194,10 +1194,7 @@ signature_algs_ext(undefined) ->
signature_algs_ext(SignatureSchemes0) ->
%% The SSL option signature_algs contains both hash-sign algorithms (tuples) and
%% signature schemes (atoms) if TLS 1.3 is configured.
- %% Filter out all hash-sign tuples when creating the signature_algs extension.
- %% (TLS 1.3 specific record type)
- SignatureSchemes = lists:filter(fun is_atom/1, SignatureSchemes0),
- #signature_algorithms{signature_scheme_list = SignatureSchemes}.
+ #signature_algorithms{signature_scheme_list = SignatureSchemes0}.
signature_algs_cert(undefined) ->
undefined;
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index 27cd5765e5..f7c8c770ae 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -606,8 +606,26 @@ signature_schemes(Version, SignatureSchemes) when is_tuple(Version)
Acc
end;
%% Special clause for filtering out the legacy hash-sign tuples.
- (_ , Acc) ->
- Acc
+ ({Hash, dsa = Sign} = Alg, Acc) ->
+ case proplists:get_bool(dss, PubKeys)
+ andalso proplists:get_bool(Hash, Hashes)
+ andalso is_pair(Hash, Sign, Hashes)
+ of
+ true ->
+ [Alg | Acc];
+ false ->
+ Acc
+ end;
+ ({Hash, Sign} = Alg, Acc) ->
+ case proplists:get_bool(Sign, PubKeys)
+ andalso proplists:get_bool(Hash, Hashes)
+ andalso is_pair(Hash, Sign, Hashes)
+ of
+ true ->
+ [Alg | Acc];
+ false ->
+ Acc
+ end
end,
Supported = lists:foldl(Fun, [], SignatureSchemes),
lists:reverse(Supported);
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index ce4479020e..46e5de6ffd 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -249,6 +249,7 @@ tls13_test_group() ->
tls_record_1_3_encode_decode,
tls13_finished_verify_data,
tls13_1_RTT_handshake,
+ tls12_ssl_server_tls13_ssl_client,
tls13_basic_ssl_server_openssl_client,
tls13_basic_ssl_server_ssl_client,
tls13_basic_openssl_server_ssl_client,
@@ -5367,6 +5368,41 @@ tls13_finished_verify_data(_Config) ->
FinishedKey = tls_v1:finished_key(BaseKey, sha256),
VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages).
+
+tls12_ssl_server_tls13_ssl_client() ->
+ [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client"}].
+
+tls12_ssl_server_tls13_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2']}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {signature_algs_cert, [ecdsa_secp384r1_sha384,
+ rsa_pss_rsae_sha256,
+ rsa_pkcs1_sha256,
+ {sha256,rsa},{sha256,dsa}]}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_basic_ssl_server_openssl_client() ->
[{doc,"Test TLS 1.3 basic connection between ssl server and openssl s_client"}].
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 000c6e1ce7..09ae5ef04a 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -186,6 +186,21 @@
</section>
+<section><title>Tools 2.11.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p><c>cover</c> would fail to start if two processes
+ tried to start it at the exact same time.</p>
+ <p>
+ Own Id: OTP-15813 Aux Id: ERL-943 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 2.11.2.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/wx/c_src/wxe_driver.c b/lib/wx/c_src/wxe_driver.c
index c9d299e0df..b94ec2f32d 100644
--- a/lib/wx/c_src/wxe_driver.c
+++ b/lib/wx/c_src/wxe_driver.c
@@ -214,7 +214,7 @@ standard_outputv(ErlDrvData drv_data, ErlIOVec* ev)
if(binref == NULL) { /* realloc */
max = sd->max_bins + DEF_BINS;
- driver_realloc(sd->bin, sizeof(WXEBinRef)*max);
+ sd->bin = driver_realloc(sd->bin, sizeof(WXEBinRef)*max);
for(i=sd->max_bins; i < max; i++) {
sd->bin[i].from = 0;
}