summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yaml4
-rw-r--r--HOWTO/TESTING.md2
-rw-r--r--Makefile.in2
-rw-r--r--OTP_VERSION2
-rwxr-xr-xconfigure10
-rw-r--r--configure.src10
-rw-r--r--erts/doc/src/notes.xml19
-rw-r--r--erts/emulator/beam/beam_common.c6
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c7
-rw-r--r--erts/emulator/beam/jit/x86/instr_bs.cpp4
-rw-r--r--erts/emulator/beam/jit/x86/instr_call.cpp8
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/crypto/c_src/Makefile.in1
-rw-r--r--lib/crypto/c_src/aead.c42
-rw-r--r--lib/crypto/c_src/api_ng.c260
-rw-r--r--lib/crypto/c_src/atoms.c4
-rw-r--r--lib/crypto/c_src/atoms.h2
-rw-r--r--lib/crypto/c_src/cipher.c9
-rw-r--r--lib/crypto/c_src/common.c53
-rw-r--r--lib/crypto/c_src/common.h19
-rw-r--r--lib/crypto/c_src/crypto.c4
-rw-r--r--lib/crypto/c_src/mac.c66
-rw-r--r--lib/crypto/doc/src/notes.xml22
-rw-r--r--lib/crypto/src/crypto.erl214
-rw-r--r--lib/crypto/test/engine_SUITE.erl3
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/erl_docgen/priv/css/otp_doc.css489
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/Makefile2
-rw-r--r--lib/erl_docgen/priv/js/topbar.js16
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl519
-rw-r--r--lib/inets/doc/src/httpc.xml24
-rw-r--r--lib/inets/src/http_client/httpc.erl122
-rw-r--r--lib/inets/src/http_lib/http_request.erl196
-rw-r--r--lib/inets/test/httpc_SUITE.erl138
-rw-r--r--lib/kernel/doc/src/notes.xml19
-rw-r--r--lib/kernel/src/kernel.appup.src6
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/public_key/doc/src/notes.xml18
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/ssl/doc/src/notes.xml40
-rw-r--r--lib/ssl/doc/src/standards_compliance.xml6
-rw-r--r--lib/ssl/doc/src/using_ssl.xml6
-rw-r--r--lib/ssl/src/ssl.app.src2
-rw-r--r--lib/ssl/src/ssl_certificate.erl4
-rw-r--r--lib/ssl/src/ssl_cipher.erl154
-rw-r--r--lib/ssl/src/ssl_handshake.erl22
-rw-r--r--lib/ssl/test/openssl_client_cert_SUITE.erl52
-rw-r--r--lib/ssl/test/ssl_cert_SUITE.erl48
-rw-r--r--lib/ssl/test/ssl_test_lib.erl10
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--make/otp_release_targets.mk8
-rw-r--r--make/otp_version_tickets_in_merge16
-rw-r--r--otp_versions.table1
-rwxr-xr-xscripts/otp_html_check2
-rw-r--r--system/doc/top/Makefile8
-rw-r--r--system/doc/top/templates/index.html.src54
56 files changed, 1748 insertions, 1017 deletions
diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml
index 0f09ab3d4d..1d1f2b44bc 100644
--- a/.github/workflows/main.yaml
+++ b/.github/workflows/main.yaml
@@ -111,6 +111,8 @@ jobs:
tar -xzf ./otp_src.tar.gz
cd otp
export ERL_TOP=`pwd`
+ export MAKEFLAGS=-j4
+ export ERLC_USE_SERVER=true
eval `./otp_build env_win32 x64`
./otp_build configure
if cat erts/CONF_INFO || cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi
@@ -232,8 +234,10 @@ jobs:
TAG=${GITHUB_REF#refs/tags/}
IS_RELEASE=`$(echo $TAG | grep -E '^OTP-[0-9]+\.[0-9]+$' > /dev/null) \
&& echo "true" || echo "false"`
+ VSN=${TAG#OTP-}
echo "::set-output name=tag::${TAG}"
echo "::set-output name=release::${IS_RELEASE}"
+ echo "::set-output name=vsn::${VSN}"
- uses: actions/checkout@v2
diff --git a/HOWTO/TESTING.md b/HOWTO/TESTING.md
index 7a7f6982f2..f713f85231 100644
--- a/HOWTO/TESTING.md
+++ b/HOWTO/TESTING.md
@@ -139,7 +139,7 @@ purpose. The `make test` command works when the current directory
contains a directory called test and in the root directory of the
source code tree.
-*(Waring)* Some test cases do not run correctly or cannot be run at
+*(Warning)* Some test cases do not run correctly or cannot be run at
all through the `make test` command (typically test cases that require
test specific C code to be compiled) because `make test` runs tests
directly by invoking the `ct_run` command instead of using the `ts`
diff --git a/Makefile.in b/Makefile.in
index ab2fc77b06..bf867f66ce 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -451,7 +451,7 @@ endif
$(DOCGEN)/priv/bin/validate_links.escript $(ERL_TOP) make/$(TARGET)/mod2app.xml \
lib/*/doc/xml/*.xml erts/doc/xml/*.xml system/doc/xml/*/*.xml
-mod2app: $(ERL_TOP)/make/$(TARGET)/mod2app.xml
+mod2app: doc_bootstrap_build doc_bootstrap_copy $(ERL_TOP)/make/$(TARGET)/mod2app.xml
$(ERL_TOP)/make/$(TARGET)/mod2app.xml: erts/doc/src/Makefile lib/*/doc/src/Makefile
PATH=$(BOOT_PREFIX)"$${PATH}" escript $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen/priv/bin/xref_mod_app.escript -topdir $(ERL_TOP) -outfile $(ERL_TOP)/make/$(TARGET)/mod2app.xml
diff --git a/OTP_VERSION b/OTP_VERSION
index b3ef8a50a4..beafbdd5e8 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-24.1.1
+24.1.2
diff --git a/configure b/configure
index de7045e377..19b4b01ec8 100755
--- a/configure
+++ b/configure
@@ -55,7 +55,7 @@ skip_applications=
while test $# != 0; do
case $1 in
-srcdir=* | --srcdir=*)
- user_srcdir=`expr -- "$1" : '[^=]*=\(.*\)'`
+ user_srcdir=`echo "$1" | sed 's/^[^=]*=//'`
if test "$ERL_TOP" != ""; then
echo "WARNING: Overriding ERL_TOP with $user_srcdir" 1>&2
echo "" 1>&2
@@ -95,7 +95,7 @@ while test $# != 0; do
echo "" 1>&2
;;
-cache-file=* | --cache-file=* )
- static_cache=`expr -- "$1" : '[^=]*=\(.*\)'`
+ static_cache=`echo "$1" | sed 's/^[^=]*=//'`
if test "$static_cache" != "/dev/null"; then
echo "WARNING: Only using config cache file '$static_cache' as static cache" 1>&2
echo "" 1>&2
@@ -140,8 +140,8 @@ while test $# != 0; do
pie_ldflags="-no-pie"
;;
CFLAGS=* | LDFLAGS=*)
- flgs_var=`expr -- "$1" : '\([^=]*\)=.*'`
- flgs_val=`expr -- "$1" : '[^=]*=\(.*\)'`
+ flgs_var=`echo "$1" | sed 's/=.*$//'`
+ flgs_val=`echo "$1" | sed 's/^[^=]*=//'`
eval $flgs_var=\$flgs_val
;;
--help=r* | -help=r*)
@@ -151,7 +151,7 @@ while test $# != 0; do
*)
case $1 in
--without-*)
- skip_app=`expr -- "$1" : '--without-\(.*\)'`
+ skip_app=`echo "$1" | sed 's/^--without-//'`
if [ "$skip_app" = "stdlib" ] ||
[ "$skip_app" = "kernel" ] ||
[ "$skip_app" = "sasl" ] ||
diff --git a/configure.src b/configure.src
index 03bc4b3947..f0afd5c6ee 100644
--- a/configure.src
+++ b/configure.src
@@ -55,7 +55,7 @@ skip_applications=
while test $# != 0; do
case $1 in
-srcdir=* | --srcdir=*)
- user_srcdir=`expr -- "$1" : '[^=]*=\(.*\)'`
+ user_srcdir=`echo "$1" | sed 's/^[^=]*=//'`
if test "$ERL_TOP" != ""; then
echo "WARNING: Overriding ERL_TOP with $user_srcdir" 1>&2
echo "" 1>&2
@@ -95,7 +95,7 @@ while test $# != 0; do
echo "" 1>&2
;;
-cache-file=* | --cache-file=* )
- static_cache=`expr -- "$1" : '[^=]*=\(.*\)'`
+ static_cache=`echo "$1" | sed 's/^[^=]*=//'`
if test "$static_cache" != "/dev/null"; then
echo "WARNING: Only using config cache file '$static_cache' as static cache" 1>&2
echo "" 1>&2
@@ -140,8 +140,8 @@ while test $# != 0; do
pie_ldflags="-no-pie"
;;
CFLAGS=* | LDFLAGS=*)
- flgs_var=`expr -- "$1" : '\([^=]*\)=.*'`
- flgs_val=`expr -- "$1" : '[^=]*=\(.*\)'`
+ flgs_var=`echo "$1" | sed 's/=.*$//'`
+ flgs_val=`echo "$1" | sed 's/^[^=]*=//'`
eval $flgs_var=\$flgs_val
;;
--help=r* | -help=r*)
@@ -151,7 +151,7 @@ while test $# != 0; do
*)
case $1 in
--without-*)
- skip_app=`expr -- "$1" : '--without-\(.*\)'`
+ skip_app=`echo "$1" | sed 's/^--without-//'`
if [ "$skip_app" = "stdlib" ] ||
[ "$skip_app" = "kernel" ] ||
[ "$skip_app" = "sasl" ] ||
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index da2d96af4d..4cffeca776 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -31,6 +31,25 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 12.1.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The python scripts that existed in
+ erts/lib_src/yielding_c_fun/lib/tiny_regex_c/scripts had
+ a license that was incompatible with Erlang/OTP's
+ license. This ticket removes these scripts that were not
+ used by us.</p>
+ <p>
+ Own Id: OTP-17658</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 12.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/beam/beam_common.c b/erts/emulator/beam/beam_common.c
index 5eeb9a9807..1a1326450f 100644
--- a/erts/emulator/beam/beam_common.c
+++ b/erts/emulator/beam/beam_common.c
@@ -1300,11 +1300,7 @@ apply_setup_error_handler(Process* p, Eterm module, Eterm function, Uint arity,
* properly adjusted).
*/
- if (HeapWordsLeft(p) < sz) {
- erts_garbage_collect(p, sz, reg, arity);
- }
- hp = HEAP_TOP(p);
- HEAP_TOP(p) += sz;
+ hp = HAlloc(p, sz);
for (i = arity-1; i >= 0; i--) {
args = CONS(hp, reg[i], args);
hp += 2;
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index e638e499c9..be4ee9772d 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -3285,11 +3285,10 @@ recv_marker_insert(Process *c_p, ErtsRecvMarker *markp, int setting)
if (!setting && *c_p->sig_qs.save == (ErtsMessage *) &markp->sig) {
/*
- * This should most likely never happen (which is why the assert
- * is here), but if it does, leave the message queue in a valid
- * state...
+ * This can happen when a recv marker recently entered the message
+ * queue via erts_proc_sig_handle_incoming() through the midddle
+ * signal queue...
*/
- ASSERT(0);
markp->pass++;
c_p->sig_qs.save = c_p->sig_qs.last;
}
diff --git a/erts/emulator/beam/jit/x86/instr_bs.cpp b/erts/emulator/beam/jit/x86/instr_bs.cpp
index 7df0b84cae..6e9fc79751 100644
--- a/erts/emulator/beam/jit/x86/instr_bs.cpp
+++ b/erts/emulator/beam/jit/x86/instr_bs.cpp
@@ -1407,8 +1407,8 @@ void BeamModuleAssembler::emit_bs_add(const ArgVal &Fail,
a.and_(RETd, ARG1d);
}
}
- a.and_(RETb, imm(_TAG_PRIMARY_MASK));
- a.cmp(RETb, imm(TAG_PRIMARY_IMMED1));
+ a.and_(RETb, imm(_TAG_IMMED1_MASK));
+ a.cmp(RETb, imm(_TAG_IMMED1_SMALL));
a.jne(fail);
/* Verify that ARG2 >= 0 and multiply ARG2 by the unit. The
diff --git a/erts/emulator/beam/jit/x86/instr_call.cpp b/erts/emulator/beam/jit/x86/instr_call.cpp
index b79ef5567c..e0ee3543bd 100644
--- a/erts/emulator/beam/jit/x86/instr_call.cpp
+++ b/erts/emulator/beam/jit/x86/instr_call.cpp
@@ -136,7 +136,7 @@ x86::Mem BeamModuleAssembler::emit_variable_apply(bool includeI) {
align_erlang_cp();
a.bind(entry);
- emit_enter_runtime<Update::eStack | Update::eHeap>();
+ emit_enter_runtime<Update::eReductions | Update::eStack | Update::eHeap>();
a.mov(ARG1, c_p);
load_x_reg_array(ARG2);
@@ -151,7 +151,7 @@ x86::Mem BeamModuleAssembler::emit_variable_apply(bool includeI) {
runtime_call<4>(apply);
- emit_leave_runtime<Update::eStack | Update::eHeap>();
+ emit_leave_runtime<Update::eReductions | Update::eStack | Update::eHeap>();
a.test(RET, RET);
a.short_().jne(dispatch);
@@ -185,7 +185,7 @@ x86::Mem BeamModuleAssembler::emit_fixed_apply(const ArgVal &Arity,
mov_arg(ARG3, Arity);
- emit_enter_runtime<Update::eStack | Update::eHeap>();
+ emit_enter_runtime<Update::eReductions | Update::eStack | Update::eHeap>();
a.mov(ARG1, c_p);
load_x_reg_array(ARG2);
@@ -200,7 +200,7 @@ x86::Mem BeamModuleAssembler::emit_fixed_apply(const ArgVal &Arity,
runtime_call<5>(fixed_apply);
- emit_leave_runtime<Update::eStack | Update::eHeap>();
+ emit_leave_runtime<Update::eReductions | Update::eStack | Update::eHeap>();
a.test(RET, RET);
a.short_().jne(dispatch);
diff --git a/erts/vsn.mk b/erts/vsn.mk
index a9ffb183b6..a33a408310 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 12.1.1
+VSN = 12.1.2
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index 1af18b5879..92918b5d9f 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -93,6 +93,7 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \
$(OBJDIR)/bn$(TYPEMARKER).o \
$(OBJDIR)/cipher$(TYPEMARKER).o \
$(OBJDIR)/cmac$(TYPEMARKER).o \
+ $(OBJDIR)/common$(TYPEMARKER).o \
$(OBJDIR)/dh$(TYPEMARKER).o \
$(OBJDIR)/digest$(TYPEMARKER).o \
$(OBJDIR)/dss$(TYPEMARKER).o \
diff --git a/lib/crypto/c_src/aead.c b/lib/crypto/c_src/aead.c
index 42c3d35928..8bbeb5bec4 100644
--- a/lib/crypto/c_src/aead.c
+++ b/lib/crypto/c_src/aead.c
@@ -51,30 +51,30 @@ ERL_NIF_TERM aead_cipher_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
encflg = -1;
else
{
- ret = EXCP_BADARG(env, "Bad enc flag");
+ ret = EXCP_BADARG_N(env, 6, "Bad enc flag");
goto done;
}
type = argv[0];
if (!enif_is_atom(env, type))
- {ret = EXCP_BADARG(env, "non-atom cipher type"); goto done;}
+ {ret = EXCP_BADARG_N(env, 0, "non-atom cipher type"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
- {ret = EXCP_BADARG(env, "non-binary key"); goto done;}
+ {ret = EXCP_BADARG_N(env, 1, "non-binary key"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[2], &iv))
- {ret = EXCP_BADARG(env, "non-binary iv"); goto done;}
+ {ret = EXCP_BADARG_N(env, 2, "non-binary iv"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[3], &in))
- {ret = EXCP_BADARG(env, "non-binary text"); goto done;}
+ {ret = EXCP_BADARG_N(env, 3, "non-binary text"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[4], &aad))
- {ret = EXCP_BADARG(env, "non-binary AAD"); goto done;}
+ {ret = EXCP_BADARG_N(env, 4, "non-binary AAD"); goto done;}
if (encflg) {
if (!enif_get_uint(env, argv[5], &tag_len))
- {ret = EXCP_BADARG(env, "Bad Tag length"); goto done;}
+ {ret = EXCP_BADARG_N(env, 5, "Bad Tag length"); goto done;}
tag_data = NULL;
} else {
if (!enif_inspect_iolist_as_binary(env, argv[5], &tag))
- {ret = EXCP_BADARG(env, "non-binary Tag"); goto done;}
+ {ret = EXCP_BADARG_N(env, 5, "non-binary Tag"); goto done;}
tag_len = tag.size;
tag_data = tag.data;
}
@@ -84,16 +84,16 @@ ERL_NIF_TERM aead_cipher_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
|| iv.size > INT_MAX
|| in.size > INT_MAX
|| aad.size > INT_MAX)
- {ret = EXCP_BADARG(env, "binary too long"); goto done;}
+ {ret = EXCP_BADARG_N(env, 5, "binary too long"); goto done;}
if ((cipherp = get_cipher_type(type, key.size)) == NULL)
- {ret = EXCP_BADARG(env, "Unknown cipher"); goto done;}
+ {ret = EXCP_BADARG_N(env, 0, "Unknown cipher or invalid key size"); goto done;}
if (cipherp->flags & NON_EVP_CIPHER)
- {ret = EXCP_BADARG(env, "Bad cipher"); goto done;}
+ {ret = EXCP_BADARG_N(env, 0, "Bad cipher"); goto done;}
if (! (cipherp->flags & AEAD_CIPHER) )
- {ret = EXCP_BADARG(env, "Not aead cipher"); goto done;}
+ {ret = EXCP_BADARG_N(env, 0, "Not aead cipher"); goto done;}
if ((cipher = cipherp->cipher.p) == NULL)
- {ret = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version"); goto done;}
+ {ret = EXCP_NOTSUP_N(env, 0, "The cipher is not supported in this libcrypto version"); goto done;}
#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
if ( !encflg && (cipherp->flags & GCM_MODE))
@@ -106,27 +106,27 @@ ERL_NIF_TERM aead_cipher_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encflg) != 1)
{ret = EXCP_ERROR(env, "CipherInit failed"); goto done;}
if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_ivlen, (int)iv.size, NULL) != 1)
- {ret = EXCP_BADARG(env, "Bad IV length"); goto done;}
+ {ret = EXCP_BADARG_N(env, 2, "Bad IV length"); goto done;}
#if defined(HAVE_CCM)
if (cipherp->flags & CCM_MODE) {
if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_tag, (int)tag_len, tag_data) != 1)
- {ret = EXCP_BADARG(env, "Can't set tag"); goto done;}
+ {ret = EXCP_BADARG_N(env, 5, "Can't set tag"); goto done;}
if (EVP_CipherInit_ex(ctx, NULL, NULL, key.data, iv.data, -1) != 1)
- {ret = EXCP_BADARG(env, "Can't set key or iv"); goto done;}
+ {ret = EXCP_ERROR(env, "Can't set key or iv"); goto done;}
if (EVP_CipherUpdate(ctx, NULL, &len, NULL, (int)in.size) != 1)
- {ret = EXCP_BADARG(env, "Can't set text size"); goto done;}
+ {ret = EXCP_ERROR(env, "Can't set text size"); goto done;}
} else
#endif
{ /* GCM_MODE or CHACHA20_POLY1305 */
/* Set key and iv */
if (EVP_CipherInit_ex(ctx, NULL, NULL, key.data, iv.data, -1) != 1)
- {ret = EXCP_BADARG(env, "Can't set key or iv"); goto done;}
+ {ret = EXCP_ERROR(env, "Can't set key and iv"); goto done;}
}
/* Set the AAD */
if (EVP_CipherUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
- {ret = EXCP_BADARG(env, "Can't set AAD"); goto done;}
+ {ret = EXCP_BADARG_N(env, 4, "Can't set AAD"); goto done;}
/* Set the plain text and get the crypto text (or vice versa :) ) */
if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
@@ -134,7 +134,7 @@ ERL_NIF_TERM aead_cipher_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
if (EVP_CipherUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
{
if (encflg)
- ret = EXCP_BADARG(env, "Can't set in-text");
+ ret = EXCP_BADARG_N(env, 3, "Can't set in-text");
else
/* Decrypt error */
ret = atom_error;
@@ -182,7 +182,7 @@ done:
return ret;
#else
- return EXCP_NOTSUP(env, "Unsupported Cipher");
+ return EXCP_NOTSUP_N(env, 0, "Unsupported Cipher");
#endif
}
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c
index c2ae10f2ac..077cdda92e 100644
--- a/lib/crypto/c_src/api_ng.c
+++ b/lib/crypto/c_src/api_ng.c
@@ -85,13 +85,117 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in)
/* Get the arguments for the initialization of the EVP_CIPHER_CTX. Check */
/* them and initialize that context. */
/*************************************************************************/
+
+static ERL_NIF_TERM get_opts(ErlNifEnv* env, const ERL_NIF_TERM opts, int opts_arg_num, int *encflgp, ERL_NIF_TERM *padflgp)
+{ /* boolean() | [{Tag,Val}] Tag = encrypt | padding */
+ unsigned list_len;
+ ERL_NIF_TERM p, hd, tl;
+
+ *padflgp = atom_false; /* Not valid as padding value */
+ /* First check if the opts is an atom: */
+ if (opts == atom_true)
+ {
+ *encflgp = 1;
+ *padflgp = atom_undefined;
+ return atom_ok;
+ }
+
+ if (opts == atom_false)
+ {
+ *encflgp = 0;
+ *padflgp = atom_undefined;
+ return atom_ok;
+ }
+
+ if (opts == atom_undefined)
+ /* For compat funcs in crypto.erl. TODO: check and remove */
+ {
+ *encflgp = -1;
+ *padflgp = atom_undefined;
+ return atom_ok;
+ }
+
+ if (!enif_is_list(env, opts) || !enif_get_list_length(env, opts, &list_len))
+ /* Not a boolean() and not a list, definitly an error */
+ return EXCP_BADARG_N(env, opts_arg_num, "Options are not a boolean or a proper list");
+
+ /* A list, might be a property list, as it should */
+ *encflgp = -14; /* why not? */
+ p = opts;
+ while (enif_get_list_cell(env, p, &hd, &tl))
+ /* Loop through the list [{Tag,Value},...]
+ - check that
+ + the list is proper
+ + each list element is a 2-tuple
+ + the Tag is known
+ + the Value is of right type
+ - assign Values of known Tags to their respective flags
+ */
+ {
+ int arity;
+ const ERL_NIF_TERM* elements;
+
+ if (!(enif_get_tuple(env, hd, &arity, &elements) && (arity == 2)) )
+ return EXCP_BADARG_N(env, opts_arg_num, "Options must be a property list!");
+
+ if (elements[0] == atom_encrypt)
+ {
+ if (*encflgp != -14)
+ return EXCP_BADARG_N(env, opts_arg_num, "'encrypt' option is present more than once!");
+ else if (elements[1] == atom_true)
+ *encflgp = 1;
+ else if (elements[1] == atom_false)
+ *encflgp = 0;
+ else if (elements[1] == atom_undefined)
+ *encflgp = -1; /* For compat funcs in crypto.erl. TODO: check and remove */
+ else
+ return EXCP_BADARG_N(env, opts_arg_num, "The 'encrypt' option must be a boolean!");
+ }
+ else if (elements[0] == atom_padding)
+ {
+ if (*padflgp != atom_false)
+ return EXCP_BADARG_N(env, opts_arg_num, "The 'padding' option is present more than once!");
+
+ else if ((elements[1] == atom_undefined) ||
+ (elements[1] == atom_none) ||
+ (elements[1] == atom_zero) ||
+ (elements[1] == atom_random) ||
+ (elements[1] == atom_pkcs_padding)
+ )
+ *padflgp = elements[1];
+
+ else
+ return EXCP_BADARG_N(env, opts_arg_num, "Bad 'padding' option value");
+ }
+ else
+ {
+ char msg[64];
+ if (enif_snprintf(msg, 64, "Bad tag in option: %T", elements[0]))
+ return EXCP_BADARG_N(env, opts_arg_num, msg);
+ else
+ return EXCP_BADARG_N(env, opts_arg_num, "Bad tag in option!");
+ }
+
+ p = tl; /* prepare for handling next list element or to exit the loop */
+ }
+
+ if (*encflgp == -14)
+ *encflgp = 1; /* {encrypt,true} is the default */
+
+ if (*padflgp == atom_false)
+ *padflgp = atom_undefined; /* {padding,undefined} is the default */
+
+ return atom_ok;
+}
+
+
static int get_init_args(ErlNifEnv* env,
struct evp_cipher_ctx *ctx_res,
- const ERL_NIF_TERM cipher_arg,
- const ERL_NIF_TERM key_arg,
- const ERL_NIF_TERM ivec_arg,
- const ERL_NIF_TERM encflg_arg,
- const ERL_NIF_TERM padding_arg,
+ const ERL_NIF_TERM argv[],
+ int cipher_arg_num,
+ int key_arg_num,
+ int ivec_arg_num,
+ int opts_arg_num,
const struct cipher_type_t **cipherp,
ERL_NIF_TERM *return_term)
{
@@ -103,57 +207,53 @@ static int get_init_args(ErlNifEnv* env,
#if !defined(HAVE_EVP_AES_CTR)
ctx_res->env = NULL; /* For testing if *env should be freed after errors */
#endif
- ctx_res->padding = atom_undefined;
ctx_res->padded_size = -1;
ctx_res->size = 0;
-
- /* Fetch the flag telling if we are going to encrypt (=true) or decrypt (=false) */
- if (encflg_arg == atom_true)
- ctx_res->encflag = 1;
- else if (encflg_arg == atom_false)
- ctx_res->encflag = 0;
- else if (encflg_arg == atom_undefined)
- /* For compat funcs in crypto.erl */
- ctx_res->encflag = -1;
- else
- {
- *return_term = EXCP_BADARG(env, "Bad enc flag");
- goto err;
- }
+
+ /* Two initializations to make CodeChecker happy: it gets a bit desoriented
+ by the NIF Exception model */
+ ctx_res->encflag = 0;
+ ctx_res->padding = atom_error;
+
+ /* Fetch the options */
+ if ((*return_term =
+ get_opts(env, argv[opts_arg_num], opts_arg_num, &(ctx_res->encflag), &(ctx_res->padding))
+ ) != atom_ok)
+ goto err;
/* Fetch the key */
- if (!enif_inspect_iolist_as_binary(env, key_arg, &key_bin))
+ if (!enif_inspect_iolist_as_binary(env, argv[key_arg_num], &key_bin))
{
- *return_term = EXCP_BADARG(env, "Bad key");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "Bad key");
goto err;
}
/* Fetch cipher type */
- if (!enif_is_atom(env, cipher_arg))
+ if (!enif_is_atom(env, argv[cipher_arg_num]))
{
- *return_term = EXCP_BADARG(env, "Cipher id is not an atom");
+ *return_term = EXCP_BADARG_N(env, cipher_arg_num, "Cipher id is not an atom");
goto err;
}
- if (!(*cipherp = get_cipher_type(cipher_arg, key_bin.size)))
+ if (!(*cipherp = get_cipher_type(argv[cipher_arg_num], key_bin.size)))
{
- if (!get_cipher_type_no_key(cipher_arg))
- *return_term = EXCP_BADARG(env, "Unknown cipher");
+ if (!get_cipher_type_no_key(argv[cipher_arg_num]))
+ *return_term = EXCP_BADARG_N(env, cipher_arg_num, "Unknown cipher");
else
- *return_term = EXCP_BADARG(env, "Bad key size");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "Bad key size");
goto err;
}
if ((*cipherp)->flags & AEAD_CIPHER)
{
- *return_term = EXCP_BADARG(env, "Missing arguments for this cipher");
+ *return_term = EXCP_BADARG_N(env, cipher_arg_num, "Missing arguments for this cipher");
goto err;
}
if (CIPHER_FORBIDDEN_IN_FIPS(*cipherp))
{
- *return_term = EXCP_NOTSUP(env, "Forbidden in FIPS");
+ *return_term = EXCP_NOTSUP_N(env, cipher_arg_num, "Forbidden in FIPS");
goto err;
}
@@ -171,32 +271,34 @@ static int get_init_args(ErlNifEnv* env,
ivec_len = 16;
else {
/* Unsupported crypto */
- *return_term = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version");
+ *return_term =
+ EXCP_NOTSUP_N(env, cipher_arg_num, "Cipher not supported in this libcrypto version");
goto err;
}
}
#else
/* Normal code */
if (!((*cipherp)->cipher.p)) {
- *return_term = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version");
+ *return_term =
+ EXCP_NOTSUP_N(env, cipher_arg_num, "Cipher not supported in this libcrypto version");
goto err;
}
ivec_len = GET_IV_LEN(*cipherp);
#endif
- /* (*cipherp)->cipher.p != NULL and ivec_len has a value */
+ /* Here: (*cipherp)->cipher.p != NULL and ivec_len has a value */
/* Fetch IV */
- if (ivec_len && (ivec_arg != atom_undefined)) {
- if (!enif_inspect_iolist_as_binary(env, ivec_arg, &ivec_bin))
+ if (ivec_len && (argv[ivec_arg_num] != atom_undefined)) {
+ if (!enif_inspect_iolist_as_binary(env, argv[ivec_arg_num], &ivec_bin))
{
- *return_term = EXCP_BADARG(env, "Bad iv type");
+ *return_term = EXCP_BADARG_N(env, ivec_arg_num, "Bad iv type");
goto err;
}
if (ivec_len != ivec_bin.size)
{
- *return_term = EXCP_BADARG(env, "Bad iv size");
+ *return_term = EXCP_BADARG_N(env, ivec_arg_num, "Bad iv size");
goto err;
}
}
@@ -211,7 +313,7 @@ static int get_init_args(ErlNifEnv* env,
ERL_NIF_TERM ecount_bin;
unsigned char *outp;
if ((outp = enif_make_new_binary(env, AES_BLOCK_SIZE, &ecount_bin)) == NULL) {
- *return_term = EXCP_ERROR(env, "Can't allocate ecount_bin");
+ *return_term = EXCP_ERROR(env, "Can't allocate output data binary");
goto err;
}
memset(outp, 0, AES_BLOCK_SIZE);
@@ -223,7 +325,7 @@ static int get_init_args(ErlNifEnv* env,
}
ctx_res->state =
enif_make_copy(ctx_res->env,
- enif_make_tuple4(env, key_arg, ivec_arg, ecount_bin, enif_make_int(env, 0)));
+ enif_make_tuple4(env, argv[key_arg_num], argv[ivec_arg_num], ecount_bin, enif_make_int(env, 0)));
goto success;
} else {
/* Flag for subsequent calls that no aes_ctr compatibility code should be called */
@@ -249,27 +351,27 @@ static int get_init_args(ErlNifEnv* env,
if (!EVP_CIPHER_CTX_set_key_length(ctx_res->ctx, (int)key_bin.size))
{
- *return_term = EXCP_ERROR(env, "Can't initialize context, key_length");
+ *return_term = EXCP_ERROR_N(env, key_arg_num, "Can't initialize context, key_length");
goto err;
}
#ifdef HAVE_RC2
if (EVP_CIPHER_type((*cipherp)->cipher.p) == NID_rc2_cbc) {
if (key_bin.size > INT_MAX / 8) {
- *return_term = EXCP_BADARG(env, "To large rc2_cbc key");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "To large rc2_cbc key");
goto err;
}
if (!EVP_CIPHER_CTX_ctrl(ctx_res->ctx, EVP_CTRL_SET_RC2_KEY_BITS, (int)key_bin.size * 8, NULL)) {
- *return_term = EXCP_ERROR(env, "ctrl rc2_cbc key");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "ctrl rc2_cbc key");
goto err;
}
}
#endif
- if (ivec_arg == atom_undefined || ivec_len == 0)
+ if (argv[ivec_arg_num] == atom_undefined || ivec_len == 0)
{
if (!EVP_CipherInit_ex(ctx_res->ctx, NULL, NULL, key_bin.data, NULL, -1)) {
- *return_term = EXCP_ERROR(env, "Can't initialize key");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "Can't initialize key");
goto err;
}
}
@@ -281,20 +383,9 @@ static int get_init_args(ErlNifEnv* env,
}
/* Set padding */
- if ((padding_arg == atom_undefined) ||
- (padding_arg == atom_none) ||
- (padding_arg == atom_zero) ||
- (padding_arg == atom_random) )
+ if (ctx_res->padding != atom_pkcs_padding) /* pkcs_padding is default */
EVP_CIPHER_CTX_set_padding(ctx_res->ctx, 0);
- else if (padding_arg != atom_pkcs_padding) /* pkcs_padding is default */
- {
- *return_term = EXCP_BADARG(env, "Bad padding flag");
- goto err;
- }
-
- ctx_res->padding = padding_arg;
-
*return_term = atom_ok;
#if !defined(HAVE_EVP_AES_CTR)
@@ -309,18 +400,18 @@ static int get_init_args(ErlNifEnv* env,
/*************************************************************************/
/* Get the arguments for the EVP_CipherUpdate function, and call it. */
/*************************************************************************/
-
static int get_update_args(ErlNifEnv* env,
struct evp_cipher_ctx *ctx_res,
- const ERL_NIF_TERM indata_arg,
+ const ERL_NIF_TERM argv[],
+ int indata_arg_num,
ERL_NIF_TERM *return_term)
{
ErlNifBinary in_data_bin, out_data_bin;
int out_len, block_size;
- if (!enif_inspect_binary(env, indata_arg, &in_data_bin) )
+ if (!enif_inspect_iolist_as_binary(env, argv[indata_arg_num], &in_data_bin) )
{
- *return_term = EXCP_BADARG(env, "Bad 2:nd arg");
+ *return_term = EXCP_BADARG_N(env, indata_arg_num, "Expected binary");
goto err0;
}
@@ -340,7 +431,7 @@ static int get_update_args(ErlNifEnv* env,
if (enif_get_tuple(env, state0, &tuple_argc, &tuple_argv) && (tuple_argc == 4)) {
/* A compatibility state term */
/* encrypt and decrypt is performed by calling the same function */
- newstate_and_outdata = aes_ctr_stream_encrypt_compat(env, state0, indata_arg);
+ newstate_and_outdata = aes_ctr_stream_encrypt_compat(env, state0, argv[indata_arg_num]);
if (enif_get_tuple(env, newstate_and_outdata, &tuple_argc, &tuple_argv) && (tuple_argc == 2)) {
/* newstate_and_outdata = {NewState, OutData} */
@@ -488,7 +579,11 @@ static int get_final_args(ErlNifEnv* env,
else
{
- *return_term = EXCP_ERROR(env, "Bad padding flg");
+ char msg[64];
+ if (enif_snprintf(msg, 64, "Bad padding flag: %T", ctx_res->padding))
+ *return_term = EXCP_ERROR(env, msg);
+ else
+ *return_term = EXCP_ERROR(env, "Bad padding flg");
goto err;
}
@@ -567,7 +662,7 @@ static int get_final_args(ErlNifEnv* env,
/*************************************************************************/
ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Cipher, Key, IVec, Encrypt, Padding) % if no IV for the Cipher, set IVec = <<>>
+{/* (Cipher, Key, IVec, OptionsMap) % if no IV for the Cipher, set IVec = <<>>
*/
struct evp_cipher_ctx *ctx_res = NULL;
const struct cipher_type_t *cipherp;
@@ -577,8 +672,7 @@ ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
if ((ctx_res = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL)
return EXCP_ERROR(env, "Can't allocate resource");
- if (get_init_args(env, ctx_res, argv[0], argv[1], argv[2], argv[3], argv[4],
- &cipherp, &ret))
+ if (get_init_args(env, ctx_res, argv, 0, 1, 2, 3, &cipherp, &ret))
ret = enif_make_resource(env, ctx_res);
/* else error msg in ret */
@@ -591,7 +685,7 @@ ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
else if (argv[3] == atom_false)
ctx_res->encflag = 0;
else {
- ret = EXCP_BADARG(env, "Bad enc flag");
+ ret = EXCP_BADARG_N(env, 3, "Expected true or false");
goto ret;
}
if (ctx_res->ctx) {
@@ -603,7 +697,7 @@ ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
}
ret = argv[0];
} else {
- ret = EXCP_BADARG(env, "Bad 1:st arg");
+ ret = EXCP_BADARG_N(env, 0, "Expected cipher name atom");
goto ret;
}
@@ -625,7 +719,7 @@ ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ctx_res_copy.ctx = NULL;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res))
- return EXCP_BADARG(env, "Bad 1:st arg");
+ return EXCP_BADARG_N(env, 0, "Bad State");
if (argc == 3) {
/* We have an IV in this call. Make a copy of the context */
@@ -647,13 +741,13 @@ ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
if (!enif_inspect_iolist_as_binary(env, argv[2], &ivec_bin))
{
- ret = EXCP_BADARG(env, "Bad iv type");
+ ret = EXCP_BADARG_N(env, 2, "Bad iv type");
goto err;
}
if (ctx_res_copy.iv_len != ivec_bin.size)
{
- ret = EXCP_BADARG(env, "Bad iv size");
+ ret = EXCP_BADARG_N(env, 2, "Bad iv size");
goto err;
}
@@ -676,11 +770,11 @@ ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
goto err;
}
- get_update_args(env, &ctx_res_copy, argv[1], &ret);
+ get_update_args(env, &ctx_res_copy, argv, 1, &ret);
ctx_res->size = ctx_res_copy.size;
} else
/* argc != 3, that is, argc = 2 (we don't have an IV in this call) */
- get_update_args(env, ctx_res, argv[1], &ret);
+ get_update_args(env, ctx_res, argv, 1, &ret);
err:
if (ctx_res_copy.ctx)
@@ -694,11 +788,11 @@ ERL_NIF_TERM ng_crypto_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
{/* (Context, Data [, IV]) */
ErlNifBinary data_bin;
- if (!enif_inspect_binary(env, argv[1], &data_bin))
- return EXCP_BADARG(env, "expected binary as data");
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &data_bin))
+ return EXCP_BADARG_N(env, 1, "expected binary");
if (data_bin.size > INT_MAX)
- return EXCP_BADARG(env, "to long data");
+ return EXCP_BADARG_N(env, 1, "too long data");
/* Run long jobs on a dirty scheduler to not block the current emulator thread */
if (data_bin.size > MAX_BYTES_TO_NIF) {
@@ -721,7 +815,7 @@ ERL_NIF_TERM ng_crypto_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
ERL_NIF_TERM ret;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res))
- return EXCP_BADARG(env, "Bad arg");
+ return EXCP_BADARG_N(env, 0, "Bad State");
get_final_args(env, ctx_res, &ret);
@@ -733,7 +827,7 @@ ERL_NIF_TERM ng_crypto_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
/*************************************************************************/
ERL_NIF_TERM ng_crypto_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Cipher, Key, IVec, Data, Encrypt, PaddingType) */
+{/* (Cipher, Key, IVec, Data, OptionsMap) */
struct evp_cipher_ctx ctx_res;
const struct cipher_type_t *cipherp;
ERL_NIF_TERM ret;
@@ -746,11 +840,11 @@ ERL_NIF_TERM ng_crypto_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
#endif
/* EVP_CipherInit */
- if (!get_init_args(env, &ctx_res, argv[0], argv[1], argv[2], argv[4], argv[5], &cipherp, &ret))
+ if (!get_init_args(env, &ctx_res, argv, 0, 1, 2, 4, &cipherp, &ret))
goto out;
/* out_data = EVP_CipherUpdate */
- if (!get_update_args(env, &ctx_res, argv[3], &ret))
+ if (!get_update_args(env, &ctx_res, argv, 3, &ret))
/* Got an exception as result in &ret */
goto out;
@@ -800,11 +894,11 @@ ERL_NIF_TERM ng_crypto_one_time_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
*/
ErlNifBinary data_bin;
- if (!enif_inspect_binary(env, argv[3], &data_bin))
- return EXCP_BADARG(env, "expected binary as data");
+ if (!enif_inspect_iolist_as_binary(env, argv[3], &data_bin))
+ return EXCP_BADARG_N(env, 3, "expected binary as data");
if (data_bin.size > INT_MAX)
- return EXCP_BADARG(env, "to long data");
+ return EXCP_BADARG_N(env, 3, "too long data");
/* Run long jobs on a dirty scheduler to not block the current emulator thread */
if (data_bin.size > MAX_BYTES_TO_NIF) {
@@ -827,7 +921,7 @@ ERL_NIF_TERM ng_crypto_get_data_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
ERL_NIF_TERM ret;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res))
- return EXCP_BADARG(env, "Bad arg");
+ return EXCP_BADARG_N(env, 0, "Bad State");
ret = enif_make_new_map(env);
diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c
index 5671e6d801..cae3c5287d 100644
--- a/lib/crypto/c_src/atoms.c
+++ b/lib/crypto/c_src/atoms.c
@@ -24,6 +24,8 @@ ERL_NIF_TERM atom_true;
ERL_NIF_TERM atom_false;
ERL_NIF_TERM atom_sha;
ERL_NIF_TERM atom_error;
+ERL_NIF_TERM atom_encrypt;
+ERL_NIF_TERM atom_padding;
ERL_NIF_TERM atom_pkcs_padding;
ERL_NIF_TERM atom_zero;
ERL_NIF_TERM atom_random;
@@ -165,6 +167,8 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
atom_sha = enif_make_atom(env,"sha");
atom_error = enif_make_atom(env,"error");
+ atom_encrypt = enif_make_atom(env,"encrypt");
+ atom_padding = enif_make_atom(env,"padding");
atom_pkcs_padding = enif_make_atom(env,"pkcs_padding");
atom_zero = enif_make_atom(env,"zero");
atom_random = enif_make_atom(env,"random");
diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h
index 414e3045ea..d6bdc43a52 100644
--- a/lib/crypto/c_src/atoms.h
+++ b/lib/crypto/c_src/atoms.h
@@ -28,6 +28,8 @@ extern ERL_NIF_TERM atom_true;
extern ERL_NIF_TERM atom_false;
extern ERL_NIF_TERM atom_sha;
extern ERL_NIF_TERM atom_error;
+extern ERL_NIF_TERM atom_encrypt;
+extern ERL_NIF_TERM atom_padding;
extern ERL_NIF_TERM atom_pkcs_padding;
extern ERL_NIF_TERM atom_zero;
extern ERL_NIF_TERM atom_random;
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index 5e7fc88d72..284ea0ba81 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -317,10 +317,13 @@ const struct cipher_type_t* get_cipher_type_no_key(ERL_NIF_TERM type)
int cmp_cipher_types_no_key(const void *keyp, const void *elemp) {
const struct cipher_type_t *key = keyp;
const struct cipher_type_t *elem = elemp;
+ int ret;
- if (key->type.atom < elem->type.atom) return -1;
- else if (key->type.atom > elem->type.atom) return 1;
- else /* key->type.atom == elem->type.atom */ return 0;
+ if (key->type.atom < elem->type.atom) ret = -1;
+ else if (key->type.atom > elem->type.atom) ret = 1;
+ else /* key->type.atom == elem->type.atom */ ret = 0;
+
+ return ret;
}
diff --git a/lib/crypto/c_src/common.c b/lib/crypto/c_src/common.c
new file mode 100644
index 0000000000..e5160548c4
--- /dev/null
+++ b/lib/crypto/c_src/common.c
@@ -0,0 +1,53 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2021. 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"
+
+ERL_NIF_TERM raise_exception(ErlNifEnv* env, ERL_NIF_TERM id, int arg_num, char* explanation, char* file, int line)
+/* Ex: raise_exception(atom_badarg, 1, "Unknown cipher", "api_ng.c", 17)
+ * -> {badarg, {"api_ng.c",17}, 1, "Unknown cipher"}
+ * id = atom_error | atom_notsup | atom_badarg
+ * arg_num is the (zero-based) position in argv[]. -1 is to signal that it is undefined.
+ */
+{
+ ERL_NIF_TERM file_info, exception;
+
+ file_info = enif_make_new_map(env);
+ enif_make_map_put(env, file_info,
+ enif_make_atom(env,"c_file_name"),
+ enif_make_string(env, file, (ERL_NIF_LATIN1)),
+ &file_info);
+ enif_make_map_put(env, file_info,
+ enif_make_atom(env,"c_file_line_num"),
+ enif_make_int(env, line),
+ &file_info);
+ enif_make_map_put(env, file_info,
+ enif_make_atom(env,"c_function_arg_num"),
+ enif_make_int(env, arg_num),
+ &file_info);
+ exception =
+ enif_make_tuple3(env,
+ id,
+ file_info,
+ enif_make_string(env, explanation, (ERL_NIF_LATIN1))
+ );
+
+ return enif_raise_exception(env, exception);
+}
diff --git a/lib/crypto/c_src/common.h b/lib/crypto/c_src/common.h
index 22aa38d806..8406cd0b7c 100644
--- a/lib/crypto/c_src/common.h
+++ b/lib/crypto/c_src/common.h
@@ -37,16 +37,13 @@
/* All nif functions return a valid value or throws an exception */
-#define EXCP(Env, Id, Str) enif_raise_exception((Env), \
- enif_make_tuple3((Env), \
- (Id), \
- enif_make_tuple2((Env), \
- enif_make_string((Env),__FILE__,(ERL_NIF_LATIN1)), \
- enif_make_int((Env), __LINE__)), \
- enif_make_string((Env),(Str),(ERL_NIF_LATIN1)) ))
-
-#define EXCP_NOTSUP(Env, Str) EXCP((Env), atom_notsup, (Str))
-#define EXCP_BADARG(Env, Str) EXCP((Env), atom_badarg, (Str))
-#define EXCP_ERROR(Env, Str) EXCP((Env), atom_error, (Str))
+ERL_NIF_TERM raise_exception(ErlNifEnv* env, ERL_NIF_TERM id, int arg_num, char* explanation, char* file, int Line);
+
+
+#define EXCP_ERROR(Env, Str) raise_exception((Env), atom_error, -1, (Str), __FILE__, __LINE__)
+#define EXCP_NOTSUP(Env, Str) raise_exception((Env), atom_notsup, -1, (Str), __FILE__, __LINE__)
+#define EXCP_ERROR_N(Env, ArgNum, Str) raise_exception((Env), atom_error, (ArgNum), (Str), __FILE__, __LINE__)
+#define EXCP_NOTSUP_N(Env, ArgNum, Str) raise_exception((Env), atom_notsup, (ArgNum), (Str), __FILE__, __LINE__)
+#define EXCP_BADARG_N(Env, ArgNum, Str) raise_exception((Env), atom_badarg, (ArgNum), (Str), __FILE__, __LINE__)
#endif /* E_COMMON_H__ */
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index f07ffdfedd..65804bf6fb 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -79,12 +79,12 @@ static ErlNifFunc nif_funcs[] = {
{"mac_update_nif", 2, mac_update_nif, 0},
{"mac_final_nif", 1, mac_final_nif, 0},
{"cipher_info_nif", 1, cipher_info_nif, 0},
- {"ng_crypto_init_nif", 5, ng_crypto_init_nif, 0},
+ {"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0},
{"ng_crypto_update_nif", 2, ng_crypto_update_nif, 0},
{"ng_crypto_update_nif", 3, ng_crypto_update_nif, 0},
{"ng_crypto_final_nif", 1, ng_crypto_final_nif, 0},
{"ng_crypto_get_data_nif", 1, ng_crypto_get_data_nif, 0},
- {"ng_crypto_one_time_nif", 6, ng_crypto_one_time_nif, 0},
+ {"ng_crypto_one_time_nif", 5, ng_crypto_one_time_nif, 0},
{"strong_rand_bytes_nif", 1, strong_rand_bytes_nif, 0},
{"strong_rand_range_nif", 1, strong_rand_range_nif, 0},
{"rand_uniform_nif", 2, rand_uniform_nif, 0},
diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c
index 8735158a01..13bd2815b1 100644
--- a/lib/crypto/c_src/mac.c
+++ b/lib/crypto/c_src/mac.c
@@ -176,10 +176,10 @@ ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifBinary text;
if (!enif_inspect_iolist_as_binary(env, argv[3], &text))
- return EXCP_BADARG(env, "Bad text");
+ return EXCP_BADARG_N(env, 3, "Bad text");
if (text.size > INT_MAX)
- return EXCP_BADARG(env, "Too long text");
+ return EXCP_BADARG_N(env, 3, "Too long text");
/* Run long jobs on a dirty scheduler to not block the current emulator thread */
if (text.size > MAX_BYTES_TO_NIF) {
@@ -213,28 +213,28 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
*/
if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin))
{
- return_term = EXCP_BADARG(env, "Bad key");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key");
goto err;
}
if (!enif_inspect_iolist_as_binary(env, argv[3], &text))
{
- return_term = EXCP_BADARG(env, "Bad text");
+ return_term = EXCP_BADARG_N(env, 3, "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");
+ return_term = EXCP_BADARG_N(env, 0, "Unknown mac algorithm");
else
- return_term = EXCP_BADARG(env, "Bad key length");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key length");
goto err;
}
if (MAC_FORBIDDEN_IN_FIPS(macp))
{
- return_term = EXCP_NOTSUP(env, "MAC algorithm forbidden in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 0, "MAC algorithm forbidden in FIPS");
goto err;
}
@@ -256,17 +256,17 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if ((digp = get_digest_type(argv[1])) == NULL)
{
- return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC");
+ return_term = EXCP_BADARG_N(env, 1, "Bad digest algorithm for HMAC");
goto err;
}
if (digp->md.p == NULL)
{
- return_term = EXCP_NOTSUP(env, "Unsupported digest algorithm");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported digest algorithm");
goto err;
}
if (DIGEST_FORBIDDEN_IN_FIPS(digp))
{
- return_term = EXCP_NOTSUP(env, "Digest algorithm for HMAC forbidden in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 1, "Digest algorithm for HMAC forbidden in FIPS");
goto err;
}
md = digp->md.p;
@@ -300,22 +300,22 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
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");
+ return_term = EXCP_BADARG_N(env, 1, "Unknown cipher");
else
/* Cipher exists, so it must be the key size that is wrong */
- return_term = EXCP_BADARG(env, "Bad key size");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key size");
goto err;
}
if (CIPHER_FORBIDDEN_IN_FIPS(cipherp))
{
- return_term = EXCP_NOTSUP(env, "Cipher algorithm not supported in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 1, "Cipher algorithm not supported in FIPS");
goto err;
}
if (cipherp->cipher.p == NULL)
{
- return_term = EXCP_NOTSUP(env, "Unsupported cipher algorithm");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported cipher algorithm");
goto err;
}
@@ -349,7 +349,7 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
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");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported mac algorithm");
goto err;
}
@@ -506,22 +506,22 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
*/
if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin))
{
- return_term = EXCP_BADARG(env, "Bad key");
+ return_term = EXCP_BADARG_N(env, 2, "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");
+ return_term = EXCP_BADARG_N(env, 0, "Unknown mac algorithm");
else
- return_term = EXCP_BADARG(env, "Bad key length");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key length");
goto err;
}
if (MAC_FORBIDDEN_IN_FIPS(macp))
{
- return_term = EXCP_NOTSUP(env, "MAC algorithm forbidden in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 0, "MAC algorithm forbidden in FIPS");
goto err;
}
@@ -543,17 +543,17 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if ((digp = get_digest_type(argv[1])) == NULL)
{
- return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC");
+ return_term = EXCP_BADARG_N(env, 1, "Bad digest algorithm for HMAC");
goto err;
}
if (digp->md.p == NULL)
{
- return_term = EXCP_NOTSUP(env, "Unsupported digest algorithm");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported digest algorithm");
goto err;
}
if (DIGEST_FORBIDDEN_IN_FIPS(digp))
{
- return_term = EXCP_NOTSUP(env, "Digest algorithm for HMAC forbidden in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 1, "Digest algorithm for HMAC forbidden in FIPS");
goto err;
}
md = digp->md.p;
@@ -579,22 +579,22 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
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");
+ return_term = EXCP_BADARG_N(env, 1, "Unknown cipher");
else
/* Cipher exists, so it must be the key size that is wrong */
- return_term = EXCP_BADARG(env, "Bad key size");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key size");
goto err;
}
if (CIPHER_FORBIDDEN_IN_FIPS(cipherp))
{
- return_term = EXCP_NOTSUP(env, "Cipher algorithm not supported in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 1, "Cipher algorithm not supported in FIPS");
goto err;
}
if (cipherp->cipher.p == NULL)
{
- return_term = EXCP_NOTSUP(env, "Unsupported cipher algorithm");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported cipher algorithm");
goto err;
}
@@ -621,7 +621,7 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
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");
+ return_term = EXCP_NOTSUP_N(env, 0, "Unsupported mac algorithm");
goto err;
}
@@ -666,7 +666,7 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
#else
if (argv[0] != atom_hmac)
- return EXCP_NOTSUP(env, "Unsupported mac algorithm");
+ return EXCP_NOTSUP_N(env, 0, "Unsupported mac algorithm");
return hmac_init_nif(env, argc, argv);
#endif
@@ -679,10 +679,10 @@ ERL_NIF_TERM mac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifBinary text;
if (!enif_inspect_iolist_as_binary(env, argv[1], &text))
- return EXCP_BADARG(env, "Bad text");
+ return EXCP_BADARG_N(env, 1, "Bad text");
if (text.size > INT_MAX)
- return EXCP_BADARG(env, "Too long text");
+ return EXCP_BADARG_N(env, 1, "Too long text");
/* Run long jobs on a dirty scheduler to not block the current emulator thread */
if (text.size > MAX_BYTES_TO_NIF) {
@@ -702,10 +702,10 @@ ERL_NIF_TERM mac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifBinary text;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj))
- return EXCP_BADARG(env, "Bad ref");
+ return EXCP_BADARG_N(env, 0, "Bad ref");
if (!enif_inspect_iolist_as_binary(env, argv[1], &text))
- return EXCP_BADARG(env, "Bad text");
+ return EXCP_BADARG_N(env, 1, "Bad text");
if (EVP_DigestSignUpdate(obj->ctx, text.data, text.size) != 1)
return EXCP_ERROR(env, "EVP_DigestSignUpdate");
@@ -728,7 +728,7 @@ ERL_NIF_TERM mac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifBinary ret_bin;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj))
- return EXCP_BADARG(env, "Bad ref");
+ return EXCP_BADARG_N(env, 0, "Bad ref");
if (EVP_DigestSignFinal(obj->ctx, NULL, &size) != 1)
return EXCP_ERROR(env, "Can't get sign size");
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 3201019419..ee9c940421 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,28 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 5.0.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed minor memory leak at <c>crypto</c> module purge.</p>
+ <p>
+ Own Id: OTP-17668 Aux Id: PR-5245 </p>
+ </item>
+ <item>
+ <p>
+ Fix possible inconsistency in fips mode when linking with
+ some cryptolibs.</p>
+ <p>
+ Own Id: OTP-17672</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 5.0.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 5d72114055..473be885c9 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -42,7 +42,7 @@
-export([privkey_to_pubkey/2]).
-export([ec_curve/1, ec_curves/0]).
-export([rand_seed/1]).
-
+-export([format_error/2]).
%%%----------------------------------------------------------------
%% Removed functions.
%%
@@ -403,23 +403,47 @@
%%--------------------------------------------------------------------
-%%
-%% 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).
-
+%% Compilation and loading
%%--------------------------------------------------------------------
-compile(no_native).
-on_load(on_load/0).
-define(CRYPTO_NIF_VSN,302).
+%%--------------------------------------------------------------------
+%% When generating documentation from crypto.erl, the macro ?CRYPTO_VSN is not defined.
+%% That causes the doc generation to stop...
+-ifndef(CRYPTO_VSN).
+-define(CRYPTO_VSN, "??").
+-endif.
+
+%%--------------------------------------------------------------------
+%% Call a nif and handle an error exceptions to fit into the error handling
+%% in the Erlang shell.
+%% If not called from a shell, an error exception will be propagated.
+
+-define(nif_call(Call), ?nif_call(Call, undefined, {})).
+
+-define(nif_call(Call, ArgMap), ?nif_call(Call, undefined, ArgMap)).
+
+-define(nif_call(Call, Args0, ArgMap),
+ try Call
+ catch
+ error
+ : {Id, #{c_file_name := C_file,
+ c_file_line_num := C_line,
+ c_function_arg_num := ArgNum}, Msg}
+ : Stack when is_list(C_file),
+ is_integer(C_line),
+ is_integer(ArgNum) ->
+ error({Id, {C_file,C_line}, Msg},
+ err_find_args(Args0, Stack),
+ [{error_info, #{erl_function_arg_num => err_remap_C_argnum(ArgNum, ArgMap)}}]
+ )
+ end).
+
+%%--------------------------------------------------------------------
+%% Error if the crypto nifs not are loaded
+
-define(nif_stub,nif_stub_error(?LINE)).
nif_stub_error(Line) ->
erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}).
@@ -427,16 +451,24 @@ nif_stub_error(Line) ->
%%--------------------------------------------------------------------
%%% API
%%--------------------------------------------------------------------
-%% Crypto app version history:
-%% (no version): Driver implementation
-%% 2.0 : NIF implementation, requires OTP R14
+version() ->
+ ?CRYPTO_VSN.
+
+format_error({Ex, {C_file,C_line}, Msg}, [{_M,_F,_Args,Opts} | _CallStack]) when Ex == badarg ;
+ Ex == notsup ->
+ case proplists:get_value(error_info, Opts) of
+ #{erl_function_arg_num := ErlArgNum} ->
+ FileMsg =
+ io_lib:format("(Found in the internal file ~s at line ~p)", [C_file, C_line]),
+ case ErlArgNum of
+ undefined ->
+ #{general => [Msg," ",FileMsg]};
+ N ->#{N => Msg,
+ general => FileMsg
+ }
+ end
+ end.
-%% When generating documentation from crypto.erl, the macro ?CRYPTO_VSN is not defined.
-%% That causes the doc generation to stop...
--ifndef(CRYPTO_VSN).
--define(CRYPTO_VSN, "??").
--endif.
-version() -> ?CRYPTO_VSN.
-spec start() -> ok | {error, Reason::term()}.
start() ->
@@ -769,11 +801,9 @@ cipher_info(Type) ->
FlagOrOptions :: crypto_opts() | boolean(),
State :: crypto_state() .
crypto_init(Cipher, Key, FlagOrOptions) ->
- ng_crypto_init_nif(Cipher,
- iolist_to_binary(Key),
- <<>>,
- get_crypto_opts(FlagOrOptions)).
-
+ ?nif_call(ng_crypto_init_nif(alias(Cipher,Key), Key, <<>>, FlagOrOptions),
+ {1,2,-1,3}
+ ).
-spec crypto_init(Cipher, Key, IV, FlagOrOptions) -> State | descriptive_error()
when Cipher :: cipher_iv(),
@@ -782,40 +812,7 @@ crypto_init(Cipher, Key, FlagOrOptions) ->
FlagOrOptions :: crypto_opts(),
State :: crypto_state() .
crypto_init(Cipher, Key, IV, FlagOrOptions) ->
- ng_crypto_init_nif(Cipher,
- iolist_to_binary(Key),
- iolist_to_binary(IV),
- get_crypto_opts(FlagOrOptions)).
-
-%%%----------------------------------------------------------------
-get_crypto_opts(Options) when is_list(Options) ->
- lists:foldl(fun chk_opt/2,
- #{encrypt => true,
- padding => undefined
- },
- Options);
-get_crypto_opts(Flag) when is_boolean(Flag) ->
- #{encrypt => Flag,
- padding => undefined
- };
-get_crypto_opts(X) ->
- error({badarg,{bad_option,X}}).
-
-
-chk_opt({Tag,Val}, A) ->
- case ok_opt(Tag,Val) of
- true ->
- A#{Tag => Val};
- false ->
- error({badarg,{bad_option,{Tag,Val}}})
- end;
-chk_opt(X, _) ->
- error({badarg,{bad_option,X}}).
-
-
-ok_opt(encrypt, V) -> lists:member(V, [true, false, undefined]);
-ok_opt(padding, V) -> lists:member(V, [none, pkcs_padding, zero, random, undefined]);
-ok_opt(_, _) -> false.
+ ?nif_call(ng_crypto_init_nif(alias(Cipher,Key), Key, IV, FlagOrOptions)).
%%%----------------------------------------------------------------
-spec crypto_dyn_iv_init(Cipher, Key, FlagOrOptions) -> State | descriptive_error()
@@ -825,10 +822,10 @@ ok_opt(_, _) -> false.
State :: crypto_state() .
crypto_dyn_iv_init(Cipher, Key, FlagOrOptions) ->
%% The IV is supposed to be supplied by calling crypto_update/3
- ng_crypto_init_nif(Cipher,
- iolist_to_binary(Key),
- undefined,
- get_crypto_opts(FlagOrOptions)).
+ ?nif_call(ng_crypto_init_nif(alias(Cipher,Key), Key, undefined, FlagOrOptions),
+ [Cipher, Key, FlagOrOptions],
+ {1,2,-1,3}
+ ).
%%%----------------------------------------------------------------
%%%
@@ -842,7 +839,7 @@ crypto_dyn_iv_init(Cipher, Key, FlagOrOptions) ->
Data :: iodata(),
Result :: binary() .
crypto_update(State, Data) ->
- ng_crypto_update_nif(State, iolist_to_binary(Data)).
+ ?nif_call(ng_crypto_update_nif(State, Data)).
%%%----------------------------------------------------------------
-spec crypto_dyn_iv_update(State, Data, IV) -> Result | descriptive_error()
@@ -851,7 +848,7 @@ crypto_update(State, Data) ->
IV :: iodata(),
Result :: binary() .
crypto_dyn_iv_update(State, Data, IV) ->
- ng_crypto_update_nif(State, iolist_to_binary(Data), iolist_to_binary(IV)).
+ ?nif_call(ng_crypto_update_nif(State, Data, IV)).
%%%----------------------------------------------------------------
%%%
@@ -863,7 +860,7 @@ crypto_dyn_iv_update(State, Data, IV) ->
when State :: crypto_state(),
FinalResult :: binary() .
crypto_final(State) ->
- ng_crypto_final_nif(State).
+ ?nif_call(ng_crypto_final_nif(State)).
%%%----------------------------------------------------------------
%%%
@@ -873,7 +870,7 @@ crypto_final(State) ->
when State :: crypto_state(),
Result :: map() .
crypto_get_data(State) ->
- ng_crypto_get_data_nif(State).
+ ?nif_call(ng_crypto_get_data_nif(State)).
%%%----------------------------------------------------------------
%%%
@@ -890,11 +887,10 @@ crypto_get_data(State) ->
Result :: binary() .
crypto_one_time(Cipher, Key, Data, FlagOrOptions) ->
- ng_crypto_one_time_nif(Cipher,
- iolist_to_binary(Key),
- <<>>,
- iolist_to_binary(Data),
- get_crypto_opts(FlagOrOptions)).
+ ?nif_call(ng_crypto_one_time_nif(alias(Cipher,Key), Key, <<>>, Data, FlagOrOptions),
+ [Cipher, Key, Data, FlagOrOptions],
+ {1,2,-1,3,4}
+ ).
-spec crypto_one_time(Cipher, Key, IV, Data, FlagOrOptions) ->
@@ -907,11 +903,9 @@ crypto_one_time(Cipher, Key, Data, FlagOrOptions) ->
Result :: binary() .
crypto_one_time(Cipher, Key, IV, Data, FlagOrOptions) ->
- ng_crypto_one_time_nif(Cipher,
- iolist_to_binary(Key),
- iolist_to_binary(IV),
- iolist_to_binary(Data),
- get_crypto_opts(FlagOrOptions)).
+ ?nif_call(ng_crypto_one_time_nif(alias(Cipher,Key), Key, IV, Data, FlagOrOptions),
+ [Cipher, Key, IV, Data, FlagOrOptions],
+ {}).
%%%----------------------------------------------------------------
-spec crypto_one_time_aead(Cipher, Key, IV, InText, AAD, EncFlag::true) ->
@@ -927,7 +921,9 @@ crypto_one_time(Cipher, Key, IV, Data, FlagOrOptions) ->
OutTag :: binary().
crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, true) ->
- crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, aead_tag_len(Cipher), true).
+ ?nif_call(aead_cipher_nif(alias(Cipher,Key), Key, IV, PlainText, AAD, aead_tag_len(Cipher), true),
+ {1,2,3,4,5,-1,6}
+ ).
-spec crypto_one_time_aead(Cipher, Key, IV, InText, AAD, TagOrTagLength, EncFlag) ->
@@ -949,8 +945,10 @@ crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, true) ->
OutPlainText :: binary().
crypto_one_time_aead(Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg) ->
- aead_cipher(Cipher, iolist_to_binary(Key), IV,
- TextIn, AAD, TagOrTagLength, EncFlg).
+ ?nif_call(aead_cipher_nif(alias(Cipher,Key), Key, IV, TextIn, AAD, TagOrTagLength, EncFlg),
+ [Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg],
+ {}
+ ).
aead_tag_len(aes_ccm ) -> 12;
@@ -968,12 +966,7 @@ aead_tag_len(_) ->
%%%----------------------------------------------------------------
%%% Cipher NIFs
-ng_crypto_init_nif(Cipher, Key, IVec, #{encrypt := EncryptFlag,
- padding := Padding}) ->
- ng_crypto_init_nif(alias(Cipher,Key), Key, IVec, EncryptFlag, Padding).
-
-ng_crypto_init_nif(_Cipher, _Key, _IVec, _EncryptFlag, _Padding) -> ?nif_stub.
-
+ng_crypto_init_nif(_Cipher, _Key, _IVec, _OptionsMap) -> ?nif_stub.
ng_crypto_update_nif(_State, _Data) -> ?nif_stub.
ng_crypto_update_nif(_State, _Data, _IV) -> ?nif_stub.
@@ -982,15 +975,7 @@ ng_crypto_final_nif(_State) -> ?nif_stub.
ng_crypto_get_data_nif(_State) -> ?nif_stub.
-ng_crypto_one_time_nif(Cipher, Key, IVec, Data, #{encrypt := EncryptFlag,
- padding := Padding}) ->
- ng_crypto_one_time_nif(alias(Cipher,Key), Key, IVec, Data, EncryptFlag, Padding).
-
-ng_crypto_one_time_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlag, _Padding) -> ?nif_stub.
-
-%% The default tag length is EVP_GCM_TLS_TAG_LEN(16),
-aead_cipher(Cipher, Key, IVec, AAD, In, TagOrLength, EncFlg) ->
- aead_cipher_nif(alias(Cipher,Key), Key, IVec, AAD, In, TagOrLength, EncFlg).
+ng_crypto_one_time_nif(_Cipher, _Key, _IVec, _Data, _OptionsMap) -> ?nif_stub.
aead_cipher_nif(_Type, _Key, _Ivec, _AAD, _In, _TagOrTagLength, _EncFlg) -> ?nif_stub.
@@ -1000,13 +985,13 @@ cipher_info_nif(_Type) -> ?nif_stub.
%%% Cipher aliases
%%%
-alias(aes_cbc, Key) -> alias1(aes_cbc, size(Key));
-alias(aes_cfb8, Key) -> alias1(aes_cfb8, size(Key));
-alias(aes_cfb128, Key) -> alias1(aes_cfb128, size(Key));
-alias(aes_ctr, Key) -> alias1(aes_ctr, size(Key));
-alias(aes_ecb, Key) -> alias1(aes_ecb, size(Key));
-alias(aes_gcm, Key) -> alias1(aes_gcm, size(Key));
-alias(aes_ccm, Key) -> alias1(aes_ccm, size(Key));
+alias(aes_cbc, Key) -> alias1(aes_cbc, iolist_size(Key));
+alias(aes_cfb8, Key) -> alias1(aes_cfb8, iolist_size(Key));
+alias(aes_cfb128, Key) -> alias1(aes_cfb128, iolist_size(Key));
+alias(aes_ctr, Key) -> alias1(aes_ctr, iolist_size(Key));
+alias(aes_ecb, Key) -> alias1(aes_ecb, iolist_size(Key));
+alias(aes_gcm, Key) -> alias1(aes_gcm, iolist_size(Key));
+alias(aes_ccm, Key) -> alias1(aes_ccm, iolist_size(Key));
alias(Alg, _) -> Alg.
@@ -2511,3 +2496,24 @@ choose_otp_test_engine([LibName | T], Type, Acc) ->
end;
choose_otp_test_engine([], _, Acc) ->
Acc.
+
+%%%----------------------------------------------------------------
+%%% Error internals
+
+err_find_args(undefined, [{?MODULE,_F,Args,_Info}|_]) -> Args;
+err_find_args(Args, _) -> Args.
+
+
+err_remap_C_argnum(ArgNum, ArgMap) ->
+ try
+ element(ArgNum + 1, ArgMap) % 0-numbered in C-file's argv[], 1-numbered in the tuple
+ of
+ N when is_integer(N), N>0 -> N;
+ _ -> undefined
+ catch
+ error:badarg when ArgNum >= 0 -> ArgNum+1; % short ArgMap
+ error:badarg -> undefined
+ end.
+
+
+%%%----------------------------------------------------------------
diff --git a/lib/crypto/test/engine_SUITE.erl b/lib/crypto/test/engine_SUITE.erl
index e75485f2bf..677b0c35f8 100644
--- a/lib/crypto/test/engine_SUITE.erl
+++ b/lib/crypto/test/engine_SUITE.erl
@@ -139,6 +139,9 @@ init_per_suite(Config) ->
{_, [{_,_, <<"OpenSSL 1.0.1s-freebsd 1 Mar 2016">>}]} ->
{skip, "Problem with engine on OpenSSL 1.0.1s-freebsd"};
+ {_, [{_,_,<<"LibreSSL 2.1.",_/binary>>}]} ->
+ {skip, "Problem with engine on older LibreSSL 2.1.*"};
+
{{unix,darwin}, _} ->
{skip, "Engine unsupported on Darwin"};
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index d0459ce924..806bd620b5 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 5.0.3
+CRYPTO_VSN = 5.0.4
diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css
index 915782ec8c..7a45a3a4f7 100644
--- a/lib/erl_docgen/priv/css/otp_doc.css
+++ b/lib/erl_docgen/priv/css/otp_doc.css
@@ -1,24 +1,26 @@
/* standard OTP style sheet */
+/* We use three responsive breakpoints:
+ * 768px - mobile
+ * 992px - small screen
+ * 1200px - medium screen
+ * default - large screen
+*/
body {
- background: #fefefe;
- color: #1a1a1a;
- font-family: sans-serif;
- margin: 0;
- padding: 0;
- border: 0;
- overflow: scroll;
- height: 100%;
- max-height: 100%;
- line-height: 1.2em;
- font-size: 16px;
+ background: #fefefe;
+ color: #1a1a1a;
+ font-family: sans-serif;
+ margin: 0;
+ padding: 0;
+ border: 0;
+ max-height: 100%;
+ line-height: 1.2em;
+ font-size: 16px;
}
h1, h2, h3, h4, h5, h6{
- line-height: 1.2em;
+ line-height: 1.2em;
}
-p { max-width: 42em }
-
.header { background: #222; color: #fefefe }
.top { background: #efe }
.otp { background: #efe }
@@ -31,143 +33,310 @@ a:active { color: #1c7cd6; text-decoration: none }
a:visited { color: #1b6ec2; text-decoration: none }
#container {
- width: 100%;
- margin: 0;
- background-color: #fefefe;
+ display: grid;
+ grid-template-columns: 1fr 5fr;
+ grid-template-areas: "leftnav content";
}
#leftnav {
- position: fixed;
- float: left;
- top: 0;
- bottom: 0;
- left: 0;
- width: 300px;
- overflow:auto;
- margin: 0;
- padding: 1px;
- border-right: 1px solid #ccc;
+ grid-area: leftnav;
}
-.leftnav-tube
-{
- margin: 15px;
+.leftnav-tube {
+ top: 0;
+ margin-left: 15px;
+ position: sticky;
+ height: 100vh;
+ max-width: 250px;
+ overflow: auto;
+ border-right: 1px solid #ccc;
}
#content {
- margin-left: 340px; /* set left value to WidthOfFrameDiv */
- max-width: 52em;
- overflow-x: hidden;
+ grid-area: content;
+ max-width: 52em;
+ margin-left: 30px;
+}
+
+@media screen and (max-width: 1200px) {
+ #content {
+ margin-left: 0px;
+ }
+}
+
+@media screen and (max-width: 992px) {
+ #content {
+ max-width: 35em;
+ }
+}
+
+.topbar {
+ grid-area: topbar;
+ display: none;
+}
+
+@media screen and (max-width: 768px) {
+
+ #container {
+ grid-template-columns: 100%;
+ grid-template-areas:
+ "topbar"
+ "leftnav"
+ "content";
+ }
+
+ /* styling for the top bar */
+ .topbar {
+ display: flex;
+ position: relative;
+ top: 0px;
+ padding: 0.5em;
+ width: 100%;
+ box-sizing: border-box;
+ border-bottom: 1px solid #ccc;
+ box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.05),
+ inset 0 -1px 0 rgba(0,0,0,0.15);
+ text-align: center;
+ }
+ .topbar button {
+ padding: 1 6 1 6;
+ margin: 0;
+ height: auto;
+ display: inline-block;
+ border-radius: .25rem;
+ border: 1px solid transparent;
+ background: transparent;
+ }
+ .topbar-expand:not(.show) > button {
+ /* When we add the "show" class we rotate the button 180deg */
+ transform: rotate(180deg);
+ }
+ .topbar-expand > button {
+ transition: transform 0.35s ease;
+ }
+ .topbar-expand.show-permanent > button {
+ display: none;
+ }
+ .topbar-title {
+ text-align: center;
+ flex-grow: 2;
+ }
+ .topbar-title > h1 {
+ font-size: 1.17em;
+ margin: 0px;
+ }
+
+ /* Break words on mobile */
+ #content {
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ margin-left: 0px;
+ max-width: 100%;
+ }
+ p {
+ max-width: 100%;
+ }
+ /* The h1 is part of the topbar on mobile */
+ #content h1 {
+ display: none;
+ }
+
+ /* Styling of the navbar when shown/hidden */
+ #leftnav {
+ overflow: hidden;
+ }
+ #leftnav:not(.show) {
+ max-height: 0px;
+ border-bottom: 0px;
+ transition: max-height 0.35s ease;
+ }
+ #leftnav.show {
+ max-height: 60vh;
+ border-bottom: 1px solid #ccc;
+ box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.05),
+ inset 0 -1px 0 rgba(0,0,0,0.15);
+ transition: max-height 0.35s ease;
+ }
+
+ .leftnav-tube {
+ max-height: 60vh;
+ max-width: 100%;
+ position: unset;
+ border-right: 0px;
+ margin-right: 0px;
+ margin-left: 0px;
+ padding: 0px 15px 0px 15px;
+ }
+ #leftnav.show-permanent {
+ max-height: none;
+ }
+ .show-permanent > .leftnav-tube {
+ overflow: initial;
+ max-height: none;
+ height: inherit;
+ }
+ .hide-mobile {
+ opacity: 0;
+ }
+
+}
+
+@media (prefers-reduced-motion: reduce){
+ #leftnav.collapsing{
+ transition: none;
+ }
+ .topbar-expand > button {
+ transition: none;
+ }
+}
+
+.frontpage {
+ padding-top: 50px; /* Magins for inner DIV inside each DIV (to provide padding) */
+}
+
+.mobile-only {
+ display: none;
+}
+
+@media screen and (max-width: 768px) {
+ .mobile-only {
+ display: revert;
+ }
+}
+
+.innertube, .exports-tube {
+ margin-left: 15px;
+ margin-right: 15px;
+}
+
+@media screen and (max-width: 1200px) {
+ .innertube, .exports-tube {
+ margin-left: 0px;
+ margin-right: 15px;
+ }
+}
+
+@media screen and (max-width: 768px) {
+ .innertube, .exports-tube {
+ margin-left: 15px;
+ margin-right: 15px;
+ }
+}
+
+.footer {
+ margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
+ text-align: center;
}
-.frontpage
-{
- padding-top: 50px; /* Magins for inner DIV inside each DIV (to provide padding) */
-}
+.bold_code { font-family: mono, Courier, monospace; font-weight: bold }
-.innertube
-{
- margin-left: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
- margin-right: 11em;
+.title-link {
+ display: flex;
}
-.footer
-{
- margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
- text-align: center;
+.cref-head, .func-head, .data-type-name {
+ margin: 0 0 0 -4em;
+ padding-bottom: 0.2em;
+ padding-top: 0.2em;
}
-.bold_code { font-family: mono, Courier, monospace; font-weight: bold }
-
-/* Invisible table for function specs,
- * just to get since-version out in right margin */
-.func-table, .func-tr, .func-td, .cfunc-td, .func-since-td {
- width: 100%;
- border: 0;
- padding: 0;
+.cref-head h4, .func-head h4, .data-type-name h4 {
margin: 0;
}
-.func-tr:nth-child(n) {
- background: inherit /* turn off zebra striped rows */
-}
-
-.func-td {
- width: 38em;
+.cref-head:hover, .func-head:hover, .data-type-name:hover {
+ background-color: #f5f5f5;
}
-.cfunc-td {
- width: 31em;
+/* This small trick is in order to make all but the first line of the function
+ * head indented by 7em. So that it looks like this:
+ * int enif_alloc_binary(
+ * size_t size,
+ * ErlNifBinary* bin)
+ */
+.cref-head .title-name {
padding-left: 7em;
text-indent: -7em;
}
-.func-since-td {
- width: auto;
- padding-left: 1em;
+.title-since {
+ margin-left: auto;
}
-.func-td:hover {
- background-color: #f5f5f5;
+@media screen and (max-width: 768px) {
+ .cref-head, .func-head, .data-type-name {
+ margin-left: 0em;
+ padding-bottom: 0em;
+ padding-top: 0em;
+ }
+ .title-link {
+ flex-direction: column;
+ }
+ .title-anchors {
+ display: none;
+ }
+ .title-since {
+ margin-left: 1em;
+ }
}
.code {
- font-family: mono, Courier, monospace;
- font-weight: normal;
- background-color: #f3f3f3;
+ font-family: mono, Courier, monospace;
+ font-weight: normal;
+ background-color: #f3f3f3;
}
.note, .warning, .do, .dont {
- border: 1px solid #495057;
- margin: 1em 0;
+ border: 1px solid #495057;
+ margin: 1em 0;
}
.note .label {
- background-color: #2b8a3e;
- color: #fefefe;
- font-weight: bold;
- padding: 0.5em 1em;
+ background-color: #2b8a3e;
+ color: #fefefe;
+ font-weight: bold;
+ padding: 0.5em 1em;
}
.note .content {
- background: #f8f9fa;
- line-height: 120%;
- font-size: 0.9em;
- padding: 0.5em 1em;
+ background: #f8f9fa;
+ line-height: 120%;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.warning .label {
- background: #c92a2a;
- color: #fefefe;
- font-weight: bold;
- padding: 0.5em 1em;
+ background: #c92a2a;
+ color: #fefefe;
+ font-weight: bold;
+ padding: 0.5em 1em;
}
.warning .content {
- background-color: #f8f9fa;
- line-height: 120%;
- font-size: 0.9em;
- padding: 0.5em 1em;
+ background-color: #f8f9fa;
+ line-height: 120%;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.do .label {
- background-color: #2b8a3e;
- color: #fefefe;
- font-weight: bold;
- padding: 0.5em 1em;
+ background-color: #2b8a3e;
+ color: #fefefe;
+ font-weight: bold;
+ padding: 0.5em 1em;
}
.do .content {
- background: #f8f9fa;
- line-height: 120%;
- font-size: 0.9em;
- padding: 0.5em 1em;
+ background: #f8f9fa;
+ line-height: 120%;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.dont .label {
- background: #c92a2a;
- color: #fefefe;
- font-weight: bold;
- padding: 0.5em 1em;
+ background: #c92a2a;
+ color: #fefefe;
+ font-weight: bold;
+ padding: 0.5em 1em;
}
.dont .content {
- background-color: #f8f9fa;
- line-height: 120%;
- font-size: 0.9em;
- padding: 0.5em 1em;
+ background-color: #f8f9fa;
+ line-height: 120%;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.quote {
@@ -175,61 +344,70 @@ a:visited { color: #1b6ec2; text-decoration: none }
}
.example {
- background-color:#f1f3f5;
- border: 1px solid #dee2e6;
- padding: 0.5em 1em;
- margin: 1em 0;
- font-size: 0.7em;
+ background-color:#f1f3f5;
+ border: 1px solid #dee2e6;
+ padding: 0.5em 1em;
+ margin: 1em 0;
+ font-size: 0.7em;
+ overflow-x: auto;
+ max-width: min(100%, 48em);
}
.extrafrontpageinfo {
- color: #C00;
- font-weight: bold;
- font-size: 1.2em;
+ color: #C00;
+ font-weight: bold;
+ font-size: 1.2em;
}
pre {
- font-family: mono, Courier, monospace;
- font-weight: normal;
- margin: 0;
+ font-family: mono, Courier, monospace;
+ font-weight: normal;
+ margin: 0;
}
-.data-types-body, .REFBODY{
- margin-left: 2em;
+.data-types-body, .REFBODY {
+ margin-left: 2em;
}
.REFTYPES { margin-left: 1.5em }
.exports-body {
margin-left: 3em;
}
-.exports-tube
-{
- margin-right: 11em;
+
+@media screen and (max-width: 768px) {
+ .data-types-body, .REFBODY{
+ margin-left: 1em;
+ }
+ .REFTYPES { margin-left: 0.75em }
+ .exports-body {
+ margin-left: 1em;
+ }
}
footer { }
.erlang-logo-wrapper{
- text-align: center;
- margin-bottom: 1em;
+ text-align: center;
+ margin-top: 1em;
+ margin-bottom: 1em;
}
.main-title{
- text-align: center;
+ text-align: center;
}
.main-description{
- text-align: center;
- margin: 2em 0;
- font-size: 1.5em;
- line-height: 1.5em;
+ text-align: center;
+ margin: 2em 0;
+ font-size: 1.5em;
+ line-height: 1.5em;
}
.doc-table-wrapper, .doc-image-wrapper{
- width: 100%;
+ width: 100%;
}
.doc-image-wrapper{
- text-align: center;
+ text-align: center;
}
.doc-svg {
@@ -237,60 +415,60 @@ footer { }
}
.doc-table, .doc-image{
- min-width: 50%;
- margin: 0 auto;
- font-size: 0.7em;
+ min-width: 50%;
+ margin: 0 auto;
+ font-size: 0.7em;
}
.doc-table-caption, .doc-image-caption{
- margin-top: 1em;
- font-style: italic;
- text-align: center;
+ margin-top: 1em;
+ font-style: italic;
+ text-align: center;
}
table {
- border-collapse: collapse;
- min-width: 50%;
- margin: 1em;
+ border-collapse: collapse;
+ min-width: 50%;
+ margin: 1em;
}
table, th, td {
- border: 1px solid #666;
+ border: 1px solid #666;
}
th, td {
- padding: 0.5em;
- text-align: left;
+ padding: 0.5em;
+ text-align: left;
}
tr:hover {
- background-color: #f5f5f5;
+ background-color: #f5f5f5;
}
tr:nth-child(even) {
- background-color: #f2f2f2;
+ background-color: #f2f2f2;
}
th {
- background-color: #777;
- color: #fefefe;
+ background-color: #777;
+ color: #fefefe;
}
.section-title, .section-subtitle, .section-version{
- text-align: center;
- margin: 0;
+ text-align: center;
+ margin: 0;
}
.section-title{
- font-weight: bold;
+ font-weight: bold;
}
.section-version{
- font-size: small;
+ font-size: small;
}
.expand-collapse-items{
- font-size: small;
+ font-size: small;
}
.title_link {
@@ -299,7 +477,6 @@ th {
}
.ghlink-before {
- margin-left: -4em;
visibility: hidden;
}
@@ -340,24 +517,24 @@ th {
}
hr{
- border: 0;
- border-top: 1px solid #aaa;
+ border: 0;
+ border-top: 1px solid #aaa;
}
.section-links, .panel-sections, .expand-collapse-items{
- padding: 0 1em;
+ padding: 0 1em;
}
.section-links, .panel-sections{
- margin-top: 0;
+ margin-top: 0;
}
a > .code {
- color: #1862ab;
+ color: #1862ab;
}
.func-types-title{
- font-size: 1em;
+ font-size: 1em;
}
.since{
diff --git a/lib/erl_docgen/priv/js/flipmenu/Makefile b/lib/erl_docgen/priv/js/flipmenu/Makefile
index be0bed74fb..33cce4e6d6 100644
--- a/lib/erl_docgen/priv/js/flipmenu/Makefile
+++ b/lib/erl_docgen/priv/js/flipmenu/Makefile
@@ -76,7 +76,7 @@ release_spec: opt
release_html_spec: html
$(INSTALL_DIR) "$(RELEASE_PATH)/doc/js/flipmenu"
$(INSTALL_DATA) $(JS_FILES) $(GIF_FILES) "$(RELEASE_PATH)/doc/js/flipmenu"
- $(INSTALL_DATA) ../highlight.js ../highlight.pack.js "$(RELEASE_PATH)/doc/js/"
+ $(INSTALL_DATA) ../highlight.js ../highlight.pack.js ../topbar.js "$(RELEASE_PATH)/doc/js/"
release_docs_spec: $(DOC_TARGETS:%=release_%_spec)
diff --git a/lib/erl_docgen/priv/js/topbar.js b/lib/erl_docgen/priv/js/topbar.js
new file mode 100644
index 0000000000..ef36f09c8c
--- /dev/null
+++ b/lib/erl_docgen/priv/js/topbar.js
@@ -0,0 +1,16 @@
+
+function toggleDisplay() {
+ var leftnav=document.getElementById('leftnav');
+ var topbar=document.getElementsByClassName('topbar-expand')[0];
+ if (leftnav.classList.contains('show')) {
+ leftnav.classList.remove('show');
+ topbar.classList.remove('show');
+ setTimeout(() => {
+ leftnav.classList.add('hide-mobile');
+ }, 350);
+ } else {
+ leftnav.classList.add('show');
+ topbar.classList.add('show');
+ leftnav.classList.remove('hide-mobile');
+ }
+}
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index 655d1a61e8..730c5d1447 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -229,30 +229,22 @@
<xsl:variable name="curModule" select="ancestor::erlref/module"/>
<xsl:variable name="mfas"
select="key('mfa',
- concat($curModule,':',$name,'/',$arity))"/>
- <xsl:choose>
- <xsl:when test="generate-id($mfas[1]) != generate-id(.)">
- <!-- Avoid duplicated anchors. See also menu.funcs. -->
- </xsl:when>
- <xsl:otherwise>
- <a name="{$name}-{$arity}"></a>
- </xsl:otherwise>
- </xsl:choose>
+ concat($curModule,':',$name,'/',$arity))"/>
<!-- Insert an anchor for "anchor" attribute -->
<xsl:if test="string-length($anchor) > 0">
- <a name="{$anchor}"></a>
+ <a name="{$anchor}"></a>
</xsl:if>
<xsl:variable name="global_types" select="ancestor::erlref/datatypes"/>
<xsl:variable name="local_types"
select="../type[string-length(@name) > 0]"/>
- <xsl:apply-templates select="$spec/contract/clause/head">
- <xsl:with-param name="ghlink" select="ancestor-or-self::*[@ghlink]/@ghlink"/>
- <xsl:with-param name="local_types" select="$local_types"/>
- <xsl:with-param name="global_types" select="$global_types"/>
- <xsl:with-param name="since" select="$since"/>
- </xsl:apply-templates>
+ <xsl:apply-templates select="$spec/contract/clause/head">
+ <xsl:with-param name="ghlink" select="ancestor-or-self::*[@ghlink]/@ghlink"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ <xsl:with-param name="since" select="$since"/>
+ </xsl:apply-templates>
</xsl:when>
</xsl:choose>
</xsl:template>
@@ -264,31 +256,51 @@
<xsl:param name="since"/>
<xsl:variable name="mfa" select="concat(concat(../../../name,'-'),../../../arity)"/>
<xsl:variable name="id" select="concat(concat($mfa,'-'),generate-id(.))"/>
- <table class="func-table">
- <tr class="func-tr">
- <td class="func-td">
- <div class="bold_code func-head"
- onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
- onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
- <xsl:call-template name="ghlink">
+ <h4 id="{$mfa}" class="bold_code title-link func-head"
+ onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
+ onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
+ <div class="title-anchors">
+ <xsl:call-template name="ghlink">
<xsl:with-param name="mfa" select="$mfa"/>
<xsl:with-param name="ghlink" select="$ghlink"/>
<xsl:with-param name="id" select="$id"/>
- </xsl:call-template>
- <xsl:apply-templates mode="local_type">
+ </xsl:call-template>
+ </div>
+ <xsl:variable name="name">
+ <xsl:apply-templates mode="local_type">
<xsl:with-param name="local_types" select="$local_types"/>
<xsl:with-param name="global_types" select="$global_types"/>
- </xsl:apply-templates>
- </div>
- </td>
- <td class="func-since-td">
+ </xsl:apply-templates>
+ </xsl:variable>
+ <!-- We do not include the erlang: prefix in what is selected by
+ .title-name. This is so that webcrawlers can select the true
+ function name, i.e. decode_packet instead of erlang:decode_packet.
+ -->
+ <xsl:variable name="head" select="exsl:node-set($name)/text()[1]"/>
+ <xsl:variable name="tail" select="exsl:node-set($name)/node()[position() > 1]"/>
+ <xsl:choose>
+ <xsl:when test="substring($head,1,7) = 'erlang:'">
+ <div>
+ <xsl:text>erlang:</xsl:text>
+ <span class="title-name">
+ <xsl:value-of select="substring-after($head,':')"/>
+ <xsl:copy-of select="$tail"/>
+ </span>
+ </div>
+ </xsl:when>
+ <xsl:otherwise>
+ <span class="title-name">
+ <xsl:copy-of select="$name"/>
+ </span>
+ </xsl:otherwise>
+ </xsl:choose>
<xsl:if test="string-length($since) > 0">
- <span class="since"><xsl:value-of select="$since"/>
- </span>
+ <div class="title-since">
+ <span class="since"><xsl:value-of select="$since"/>
+ </span>
+ </div>
</xsl:if>
- </td>
- </tr>
- </table>
+ </h4>
</xsl:template>
<!-- The *last* <name name="..." arity=".."/> -->
@@ -317,7 +329,7 @@
(there is no spec with more than one clause) -->
<xsl:if test="count($clause/guard) > 0 or count($type) > 0">
<div class="REFBODY fun-types">
- <h3 class="func-types-title">Types</h3>
+ <h3 id="types" class="func-types-title">Types</h3>
<xsl:choose>
<xsl:when test="$output_subtypes">
@@ -479,17 +491,15 @@
<!-- Datatype Title, is the really needed? not used by anything -->
<xsl:template match="datatype_title">
<xsl:variable name="title" select="."/>
- <h4>
- <xsl:call-template name="title_link">
- <xsl:with-param name="title"><xsl:apply-templates/></xsl:with-param>
- <xsl:with-param name="link" select="$title"/>
- </xsl:call-template>
- </h4>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title"><xsl:apply-templates/></xsl:with-param>
+ <xsl:with-param name="link" select="$title"/>
+ </xsl:call-template>
</xsl:template>
<!-- Datatype -->
<xsl:template match="datatype">
- <div class="data-types-body">
+ <article class="data-types-body">
<xsl:choose>
<xsl:when test="string-length(name/@name) > 0">
<xsl:variable name="apostrophe">'</xsl:variable>
@@ -509,15 +519,19 @@
<xsl:with-param name="by" select="$slash_encoded" />
</xsl:call-template>
</xsl:variable>
- <div class="data-type-name"
+ <h4 id="{$id}" class="title-link data-type-name"
onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
- <xsl:call-template name="ghlink">
- <xsl:with-param name="mfa" select="$id"/>
- <xsl:with-param name="id" select="$id"/>
- </xsl:call-template>
- <xsl:apply-templates select="name"/>
- </div>
+ <div class="title-anchors">
+ <xsl:call-template name="ghlink">
+ <xsl:with-param name="mfa" select="$id"/>
+ <xsl:with-param name="id" select="$id"/>
+ </xsl:call-template>
+ </div>
+ <div class="title-name">
+ <xsl:apply-templates select="name"/>
+ </div>
+ </h4>
</xsl:when>
<xsl:otherwise>
<div class="data-type-name">
@@ -526,7 +540,7 @@
</xsl:otherwise>
</xsl:choose>
<div class="data-type-desc"><xsl:apply-templates select="desc"/></div>
- </div>
+ </article>
</xsl:template>
<!-- The "mode" attribute of apply has been used to separate the case
@@ -774,6 +788,8 @@
<xsl:param name="curModule"/>
<html>
<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1"></meta>
+ <meta charset="utf-8"></meta>
<xsl:choose>
<xsl:when test="string-length($stylesheet) > 0">
<link rel="stylesheet" href="{$topdocdir}/{$stylesheet}" type="text/css"/>
@@ -792,32 +808,18 @@
</xsl:choose>
</head>
<body>
-
<div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/>
<script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script>
+ <script id="js3" type="text/javascript" src="{$topdocdir}/js/topbar.js"></script>
<script language="JavaScript" type="text/javascript">
<xsl:text disable-output-escaping="yes"><![CDATA[
<!--
- function getWinHeight() {
- var myHeight = 0;
- if( typeof( window.innerHeight ) == 'number' ) {
- //Non-IE
- myHeight = window.innerHeight;
- } else if( document.documentElement && ( document.documentElement.clientWidth ||
- document.documentElement.clientHeight ) ) {
- //IE 6+ in 'standards compliant mode'
- myHeight = document.documentElement.clientHeight;
- } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
- //IE 4 compatible
- myHeight = document.body.clientHeight;
- }
- return myHeight;
- }
-
function setscrollpos() {
- var objf=document.getElementById('loadscrollpos');
- document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2;
+ var objf = document.getElementById('loadscrollpos');
+ if (objf) {
+ document.getElementById("leftnav").firstChild.scrollTop = objf.offsetTop - 10;
+ }
}
function addEvent(obj, evType, fn){
@@ -834,8 +836,41 @@
addEvent(window, 'load', setscrollpos);
- //-->]]></xsl:text>
+ //-->
+]]></xsl:text>
</script>
+ <div class="topbar">
+ <xsl:variable name="show">
+ <xsl:if test="(local-name() = 'application') or (local-name() = 'part') or (local-name() = 'releasenotes')">
+ <!-- For index pages we want to always show the navbar for mobile -->
+ <xsl:text>show show-permanent</xsl:text>
+ </xsl:if>
+ </xsl:variable>
+ <div class="topbar-expand {$show}">
+ <button onclick="toggleDisplay();">
+ <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54" width="24" height="24">
+ <g>
+ <path style="fill:#000000;" d="M27,54c-0.552,0-1-0.448-1-1V8c0-0.552,0.448-1,1-1s1,0.448,1,1v45C28,53.552,27.552,54,27,54z"/>
+ <path style="fill:#000000;" d="M11,25c-0.256,0-0.512-0.098-0.707-0.293c-0.391-0.391-0.391-1.023,0-1.414l16-16
+ c0.391-0.391,1.023-0.391,1.414,0s0.391,1.023,0,1.414l-16,16C11.512,24.902,11.256,25,11,25z"/>
+ <path style="fill:#000000;" d="M43,25c-0.256,0-0.512-0.098-0.707-0.293l-16-16c-0.391-0.391-0.391-1.023,0-1.414
+ s1.023-0.391,1.414,0l16,16c0.391,0.391,0.391,1.023,0,1.414C43.512,24.902,43.256,25,43,25z"/>
+ <path style="fill:#000000;" d="M43,2H11c-0.552,0-1-0.448-1-1s0.448-1,1-1h32c0.552,0,1,0.448,1,1S43.552,2,43,2z"/>
+ </g>
+ </svg>
+ </button>
+ </div>
+ <div class="topbar-title">
+ <h1 id="{header/title}">
+ <xsl:if test="string-length($chapnum) > 0">
+ <xsl:value-of select="$chapnum"/>&#160;
+ </xsl:if>
+ <xsl:value-of select="header/title"/>
+ </h1>
+ </div>
+ <div class="search-expand {$show}">
+ </div>
+ </div>
<!-- Generate menu -->
<xsl:call-template name="menu">
<xsl:with-param name="chapnum" select="$chapnum"/>
@@ -913,10 +948,22 @@
<xsl:template name="menu">
<xsl:param name="chapnum"/>
<xsl:param name="curModule"/>
+ <xsl:variable name="show">
+ <xsl:choose>
+ <xsl:when test="(local-name() = 'application') or (local-name() = 'part') or (local-name() = 'releasenotes')">
+ <!-- For index pages we want to always show the navbar for mobile -->
+ <xsl:text>show show-permanent</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>hide-mobile</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
<xsl:if test="(local-name() = 'part') or ((local-name() = 'chapter') and ancestor::part)">
<!-- .../part or .../part/chapter -->
<xsl:call-template name="menu.ug">
<xsl:with-param name="chapnum" select="$chapnum"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:if>
@@ -930,12 +977,14 @@
<!-- .../internal or .../internal/chapter -->
<xsl:call-template name="menu.internal.ug">
<xsl:with-param name="chapnum" select="$chapnum"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="(local-name() = 'internal' and descendant::erlref) or (((local-name() = 'erlref') or (local-name() = 'comref') or (local-name() = 'cref') or (local-name() = 'fileref') or (local-name() = 'appref')) and ancestor::internal)">
<!-- .../internal,.../internal/erlref, .../internal/comref or .../internal/cref or .../internal/fileref or .../internal/appref -->
<xsl:call-template name="menu.internal.ref">
<xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
@@ -943,12 +992,14 @@
<!-- .../application,.../application/erlref, .../application/comref or .../application/cref or .../application/fileref or .../application/appref -->
<xsl:call-template name="menu.ref">
<xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="(local-name() = 'releasenotes') or ((local-name() = 'chapter') and ancestor::releasenotes)">
<!-- releasenotes -->
<xsl:call-template name="menu.rn">
<xsl:with-param name="chapnum" select="$chapnum"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
@@ -981,7 +1032,7 @@
<li><a href="internal_docs.html">Internal Documentation</a></li>
</xsl:if>
<xsl:if test="boolean(/book/releasenotes)">
- <li><a href="release_notes.html">Release Notes</a></li>
+ <li><a href="notes.html">Release Notes</a></li>
</xsl:if>
<xsl:choose>
<xsl:when test="string-length($pdfname) > 0">
@@ -1050,17 +1101,16 @@
<!-- Chapter/Section, subsection level 1-->
<xsl:template match="chapter/section">
<xsl:param name="chapnum"/>
- <h3>
- <xsl:for-each select="marker">
- <xsl:call-template name="marker-before-title"/>
- </xsl:for-each>
- <xsl:call-template name="title_link">
- <xsl:with-param name="title">
- <xsl:value-of select="$chapnum"/>.<xsl:number/>&#160;
- <xsl:value-of select="title"/>
- </xsl:with-param>
- </xsl:call-template>
- </h3>
+ <xsl:for-each select="marker">
+ <xsl:call-template name="marker-before-title"/>
+ </xsl:for-each>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title">
+ <xsl:value-of select="$chapnum"/>.<xsl:number/>&#160;
+ <xsl:value-of select="title"/>
+ </xsl:with-param>
+ <xsl:with-param name="header" select="'h3'"/>
+ </xsl:call-template>
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
<xsl:with-param name="sectnum"><xsl:number/></xsl:with-param>
@@ -1071,17 +1121,15 @@
<xsl:template match="section/section">
<xsl:param name="chapnum"/>
<xsl:param name="sectnum"/>
- <h4>
- <xsl:for-each select="marker">
- <xsl:call-template name="marker-before-title"/>
- </xsl:for-each>
- <!-- xsl:value-of select="$partnum"/>.<xsl:value-of select="$chapnum"/>.<xsl:value-of select="$sectnum"/>.<xsl:number/ -->
- <xsl:call-template name="title_link">
- <xsl:with-param name="title">
- <xsl:value-of select="title"/>
- </xsl:with-param>
- </xsl:call-template>
- </h4>
+ <xsl:for-each select="marker">
+ <xsl:call-template name="marker-before-title"/>
+ </xsl:for-each>
+ <!-- xsl:value-of select="$partnum"/>.<xsl:value-of select="$chapnum"/>.<xsl:value-of select="$sectnum"/>.<xsl:number/ -->
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title">
+ <xsl:value-of select="title"/>
+ </xsl:with-param>
+ </xsl:call-template>
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:apply-templates>
@@ -1106,8 +1154,7 @@
<!-- *ref/Section -->
<xsl:template match="erlref/section|cref/section|comref/section|fileref/section|appref/section|funcs/fsdescription">
<xsl:param name="chapnum"/>
- <div class="innertube">
- <h3>
+ <section class="innertube">
<xsl:for-each select="marker">
<xsl:call-template name="marker-before-title"/>
</xsl:for-each>
@@ -1115,28 +1162,30 @@
<xsl:with-param name="title">
<xsl:value-of select="title"/>
</xsl:with-param>
+ <xsl:with-param name="header" select="'h3'"/>
</xsl:call-template>
- </h3>
- <div class="REFBODY rb-3">
- <xsl:apply-templates>
- <xsl:with-param name="chapnum" select="$chapnum"/>
- </xsl:apply-templates>
- </div>
- </div>
+ <div class="REFBODY rb-3">
+ <xsl:apply-templates>
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:apply-templates>
+ </div>
+ </section>
</xsl:template>
<!-- *ref/Subsection -->
<xsl:template match="erlref/section/section|cref/section/section|comref/section/section|fileref/section/section|appref/section/section">
<xsl:param name="chapnum"/>
<xsl:param name="sectnum"/>
- <h4>
- <xsl:value-of select="title"/>
- </h4>
- <div class="REFBODY rb-4">
- <xsl:apply-templates>
- <xsl:with-param name="chapnum" select="$chapnum"/>
- </xsl:apply-templates>
- </div>
+ <section>
+ <h4 id="{title}">
+ <xsl:value-of select="title"/>
+ </h4>
+ <div class="REFBODY rb-4">
+ <xsl:apply-templates>
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:apply-templates>
+ </div>
+ </section>
</xsl:template>
@@ -1445,9 +1494,10 @@
<!-- Menu.internal.chapter -->
<xsl:template name="menu.internal.ug">
<xsl:param name="chapnum"/>
+ <xsl:param name="show"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -1459,7 +1509,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Chapters</h3>
+ <h3 id="chapters">Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
@@ -1467,15 +1517,17 @@
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
<!-- Menu.internal.ref -->
<xsl:template name="menu.internal.ref">
<xsl:param name="curModule"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <xsl:param name="show"/>
+
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -1487,7 +1539,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Table of Contents</h3>
+ <h3 id="toc">Table of Contents</h3>
<ul class="flipMenu">
<xsl:call-template name="menu.ref2">
@@ -1496,14 +1548,15 @@
<xsl:with-param name="curModule" select="$curModule"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
<!-- Menu.internal.chapter combined when we have both modules and free-form chapters -->
<xsl:template name="menu.internal.ug_ref">
- <div id="leftnav">
- <div class="leftnav-tube">
+ <xsl:param name="show"/>
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
<p class="section-title"><xsl:value-of select="/book/header/title"/></p>
@@ -1514,7 +1567,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Chapters</h3>
+ <h3 id="chapters">Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
@@ -1522,7 +1575,7 @@
</xsl:call-template>
</ul>
- <h3>Modules</h3>
+ <h3 id="modules">Modules</h3>
<ul class="flipMenu">
<xsl:call-template name="menu.ref2">
@@ -1530,8 +1583,8 @@
<!--xsl:with-param name="genFuncMenu" select="true"/-->
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
<!--Users Guide -->
@@ -1573,9 +1626,10 @@
<!-- Menu.ug -->
<xsl:template name="menu.ug">
<xsl:param name="chapnum"/>
+ <xsl:param name="show"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -1587,7 +1641,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Chapters</h3>
+ <h3 id="chapters">Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
@@ -1595,8 +1649,8 @@
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
@@ -1681,7 +1735,7 @@
<xsl:param name="chapnum"/>
<!-- center-->
- <h1>
+ <h1 id="{header/title}">
<xsl:value-of select="$chapnum"/>&#160;<xsl:value-of select="header/title"/>
</h1>
<!-- /center-->
@@ -1735,8 +1789,10 @@
<!-- Menu.ref -->
<xsl:template name="menu.ref">
<xsl:param name="curModule"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <xsl:param name="show"/>
+
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -1748,7 +1804,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Table of Contents</h3>
+ <h3 id="toc">Table of Contents</h3>
<ul class="flipMenu">
<xsl:call-template name="menu.ref2">
@@ -1757,8 +1813,8 @@
<xsl:with-param name="curModule" select="$curModule"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
@@ -2266,18 +2322,20 @@
<xsl:template match="description">
<xsl:param name="partnum"/>
- <div class="innertube">
- <xsl:call-template name="h3_title_link">
- <xsl:with-param name="title">Description</xsl:with-param>
- </xsl:call-template>
- <div class="REFBODY description-body">
- <p>
- <xsl:apply-templates>
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </p>
- </div>
- </div>
+ <section class="description">
+ <div class="innertube">
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Description</xsl:with-param>
+ </xsl:call-template>
+ <div class="REFBODY description-body">
+ <p>
+ <xsl:apply-templates>
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
+ </p>
+ </div>
+ </div>
+ </section>
</xsl:template>
<!-- Funcs -->
@@ -2305,18 +2363,18 @@
<!-- Func -->
<xsl:template match="func">
<xsl:param name="partnum"/>
-
- <xsl:apply-templates select="name"/>
- <xsl:apply-templates
- select="name[string-length(@arity) > 0 and position()=last()]"
- mode="types"/>
-
- <div class="exports-tube">
- <xsl:apply-templates select="fsummary|type|desc">
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </div>
-
+ <article class="func">
+ <xsl:apply-templates select="name"/>
+ <xsl:apply-templates
+ select="name[string-length(@arity) > 0 and position()=last()]"
+ mode="types"/>
+
+ <div class="exports-tube">
+ <xsl:apply-templates select="fsummary|type|desc">
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
+ </div>
+ </article>
</xsl:template>
<xsl:template match="name">
@@ -2370,23 +2428,13 @@
<xsl:choose>
<xsl:when test="ancestor::cref">
- <table class="func-table">
- <tr class="func-tr">
- <td class="cfunc-td">
- <span class="bold_code bc-7">
- <xsl:call-template name="title_link">
- <xsl:with-param name="link" select="substring-before(nametext, '(')"/>
- <xsl:with-param name="where" select="'before'"/>
- </xsl:call-template>
- </span>
- </td>
- <td class="func-since-td">
- <xsl:if test="string-length(@since) > 0">
- <span class="since"><xsl:value-of select="@since"/></span>
- </xsl:if>
- </td>
- </tr>
- </table>
+ <div class="cref-head bold_code bc-7">
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="link" select="substring-before(nametext, '(')"/>
+ <xsl:with-param name="where" select="'before'"/>
+ <xsl:with-param name="since" select="@since"/>
+ </xsl:call-template>
+ </div>
</xsl:when>
<xsl:when test="ancestor::erlref">
<xsl:variable name="fname">
@@ -2418,26 +2466,16 @@
</div>
</xsl:when>
<xsl:otherwise>
- <table class="func-table">
- <tr class="func-tr">
- <td class="func-td">
- <div class="bold_code fun-type">
- <xsl:call-template name="title_link">
- <xsl:with-param name="link" select="concat(concat($fname,'-'),$arity)"/>
- <xsl:with-param name="where" select="'before'"/>
- <xsl:with-param name="title">
- <xsl:apply-templates/>
- </xsl:with-param>
- </xsl:call-template>
- </div>
- </td>
- <td class="func-since-td">
- <xsl:if test="string-length(@since) > 0">
- <span class="since"><xsl:value-of select="@since"/></span>
- </xsl:if>
- </td>
- </tr>
- </table>
+ <div class="bold_code func-head">
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="link" select="concat(concat($fname,'-'),$arity)"/>
+ <xsl:with-param name="where" select="'before'"/>
+ <xsl:with-param name="since" select="@since"/>
+ <xsl:with-param name="title">
+ <xsl:apply-templates/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </div>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
@@ -2456,7 +2494,7 @@
<xsl:if test="string-length(@name) = 0 and string-length(@variable) = 0">
<div class="REFBODY rb-5">
- <h3 class="func-types-title">Types</h3>
+ <h3 id="types" class="func-types-title">Types</h3>
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -2492,33 +2530,43 @@
<xsl:template name="h3_title_link">
<xsl:param name="title"/>
- <h3>
- <xsl:call-template name="title_link">
- <xsl:with-param name="title" select="$title"/>
- <xsl:with-param name="link" select="erl:to-link($title)"/>
- </xsl:call-template>
- </h3>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title" select="$title"/>
+ <xsl:with-param name="link" select="erl:to-link($title)"/>
+ </xsl:call-template>
</xsl:template>
<xsl:template name="title_link">
<xsl:param name="title" select="'APPLY'"/>
<xsl:param name="link" select="erl:to-link(title)"/>
<xsl:param name="where" select="'after'"/>
+ <xsl:param name="header" select="'h4'"/>
+ <xsl:param name="since"/>
<xsl:param name="ghlink" select="ancestor-or-self::*[@ghlink][position() = 1]/@ghlink"/>
<xsl:variable name="id" select="concat(concat($link,'-'), generate-id(.))"/>
- <span onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
- onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
+
+ <xsl:element name="{$header}">
+ <xsl:attribute name="id"><xsl:value-of select="$link"/></xsl:attribute>
+ <xsl:attribute name="class">title-link</xsl:attribute>
+ <xsl:attribute name="onMouseOver">
+ <xsl:text>document.getElementById('ghlink-</xsl:text><xsl:value-of select="$id"/><xsl:text>').style.visibility = 'visible';</xsl:text>
+ </xsl:attribute>
+ <xsl:attribute name="onMouseOut">
+ <xsl:text>document.getElementById('ghlink-</xsl:text><xsl:value-of select="$id"/><xsl:text>').style.visibility = 'hidden';</xsl:text>
+ </xsl:attribute>
<xsl:choose>
<xsl:when test="$where = 'before'">
- <xsl:call-template name="ghlink">
- <xsl:with-param name="mfa" select="$link"/>
- <xsl:with-param name="id" select="$id"/>
- <xsl:with-param name="ghlink" select="$ghlink"/>
- <xsl:with-param name="where" select="$where"/>
- </xsl:call-template>
+ <div class="title-anchors">
+ <xsl:call-template name="ghlink">
+ <xsl:with-param name="mfa" select="$link"/>
+ <xsl:with-param name="id" select="$id"/>
+ <xsl:with-param name="ghlink" select="$ghlink"/>
+ <xsl:with-param name="where" select="$where"/>
+ </xsl:call-template>
+ </div>
</xsl:when>
</xsl:choose>
- <a class="title_link" name="{$link}">
+ <div class="title-name">
<xsl:choose>
<xsl:when test="$title = 'APPLY'">
<xsl:apply-templates/> <!-- like <ret> and <nametext> -->
@@ -2527,18 +2575,26 @@
<xsl:copy-of select="$title"/>
</xsl:otherwise>
</xsl:choose>
- </a>
+ </div>
<xsl:choose>
<xsl:when test="$where = 'after'">
- <xsl:call-template name="ghlink">
- <xsl:with-param name="mfa" select="$link"/>
- <xsl:with-param name="id" select="$id"/>
- <xsl:with-param name="ghlink" select="$ghlink"/>
- <xsl:with-param name="where" select="$where"/>
- </xsl:call-template>
+ <div class="title-anchors">
+ <xsl:call-template name="ghlink">
+ <xsl:with-param name="mfa" select="$link"/>
+ <xsl:with-param name="id" select="$id"/>
+ <xsl:with-param name="ghlink" select="$ghlink"/>
+ <xsl:with-param name="where" select="$where"/>
+ </xsl:call-template>
+ </div>
</xsl:when>
</xsl:choose>
- </span>
+ <xsl:if test="string-length($since) > 0">
+ <div class="title-since">
+ <span class="since"><xsl:value-of select="$since"/>
+ </span>
+ </div>
+ </xsl:if>
+ </xsl:element>
</xsl:template>
<xsl:template name="ghlink">
@@ -2566,11 +2622,9 @@
<xsl:template match="desc">
<xsl:param name="partnum"/>
<div class="REFBODY rb-7">
- <p>
- <xsl:apply-templates>
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </p>
+ <xsl:apply-templates>
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
</div>
</xsl:template>
@@ -2784,9 +2838,10 @@
<!-- Menu.rn -->
<xsl:template name="menu.rn">
<xsl:param name="chapnum"/>
+ <xsl:param name="show"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -2798,7 +2853,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Chapters</h3>
+ <h3 id="chapters">Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
@@ -2806,8 +2861,8 @@
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
<!-- Special templates to calculate the arity of functions -->
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 905cfb2465..34010b25e4 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2018</year>
+ <year>2004</year><year>2021</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -67,7 +67,7 @@
<p>Type definitions that are used more than once in
this module:</p>
<p><c>boolean() = true | false</c></p>
- <p><c>string()</c> = list of ASCII characters</p>
+ <p><c>http_string()</c> = list of ASCII characters</p>
<p><c>request_id() = reference()</c></p>
<p><c>profile() = atom()</c></p>
<p><c>path() = string()</c> representing a file path or directory path</p>
@@ -90,7 +90,7 @@
<p>| <c>{url(), headers(), content_type(), body()}</c></p>
</item>
</taglist>
- <p><c>url() = string()</c> syntax according to the URI definition in
+ <p><c>url() = http_string()</c> syntax according to the URI definition in
<url href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url>,
for example <c>"http://www.erlang.org"</c></p>
<warning><p>Please note that httpc normalizes input URIs before internal processing
@@ -102,17 +102,17 @@
creating the request: <c>httpc:request("http://localhost/foo%2525bar").</c>
</p></warning>
<p><c>status_line() = {http_version(), status_code(), reason_phrase()}</c></p>
- <p><c>http_version() = string()</c>, for example, <c>"HTTP/1.1"</c></p>
+ <p><c>http_version() = http_string()</c>, for example, <c>"HTTP/1.1"</c></p>
<p><c>status_code() = integer()</c></p>
<p><c>reason_phrase() = string()</c></p>
- <p><c>content_type() = string()</c></p>
+ <p><c>content_type() = http_string()</c></p>
<p><c>headers() = [header()]</c></p>
<p><c>header() = {field(), value()}</c></p>
- <p><c>field() = string()</c></p>
- <p><c>value() = string()</c></p>
+ <p><c>field() = [byte()]</c></p>
+ <p><c>value() = binary() | iolist()</c></p>
<taglist>
<tag><c>body()</c></tag>
- <item><p>= <c>string() | binary()</c></p>
+ <item><p>= <c>http_string() | binary()</c></p>
<p>| <c>{fun(accumulator())</c></p>
<p><c> -> body_processing_result(), accumulator()}</c></p>
<p>| <c>{chunkify, fun(accumulator())</c></p>
@@ -269,7 +269,7 @@
<v>Url = url()</v>
<v>Result = {status_line(), headers(), Body} |
{status_code(), Body} | request_id()</v>
- <v>Body = string() | binary()</v>
+ <v>Body = http_string() | binary()</v>
<v>Profile = profile() | pid()</v>
<d>When started <c>stand_alone</c> only the pid can be used.</d>
<v>Reason = term()</v>
@@ -317,7 +317,7 @@
<v>body_format() = string | binary</v>
<v>Result = {status_line(), headers(), Body} |
{status_code(), Body} | request_id()</v>
- <v>Body = string() | binary()</v>
+ <v>Body = http_string() | binary()</v>
<v>Profile = profile() | pid()</v>
<d>When started <c>stand_alone</c> only the pid can be used.</d>
<v>Reason = term()</v>
@@ -549,7 +549,7 @@
<v>| {verbose, VerboseMode}</v>
<v>| {unix_socket, UnixSocket}</v>
<v>Proxy = {Hostname, Port}</v>
- <v>Hostname = string()</v>
+ <v>Hostname = http_string()</v>
<d>Example: "localhost" or "foo.bar.se"</d>
<v>Port = integer()</v>
<d>Example: 8080</d>
@@ -557,7 +557,7 @@
<v>NoProxyDesc = DomainDesc | HostName | IPDesc</v>
<v>DomainDesc = "*.Domain"</v>
<d>Example: "*.ericsson.se"</d>
- <v>IpDesc = string()</v>
+ <v>IpDesc = http_string()</v>
<d>Example: "134.138" or "[FEDC:BA98"
(all IP addresses starting with 134.138 or FEDC:BA98),
"66.35.250.150" or "[2010:836B:4179::836B:4179]" (a complete IP address).
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 00e960cf71..1fd65027ee 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2021. 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.
@@ -98,8 +98,11 @@ request(Url, Profile) ->
%%--------------------------------------------------------------------------
%% request(Method, Request, HTTPOptions, Options [, Profile]) ->
-%% {ok, {StatusLine, Headers, Body}} | {ok, {Status, Body}} |
-%% {ok, RequestId} | {error,Reason} | {ok, {saved_as, FilePath}
+%% {ok, {StatusLine, Headers, Body}}
+%% | {ok, {Status, Body}}
+%% | {ok, RequestId}
+%% | {ok, {saved_as, FilePath}
+%% | {error, Reason}
%%
%% Method - atom() = head | get | put | patch | post | trace |
%% options | delete
@@ -129,10 +132,10 @@ request(Url, Profile) ->
%% ReasonPhrase = string()
%% Headers = [Header]
%% Header = {Field, Value}
-%% Field = string()
-%% Value = string()
+%% Field = [byte()]
+%% Value = binary() | iolist()
%% Body = string() | binary() | {fun(SendAcc) -> SendFunResult, SendAcc} |
-%% {chunkify, fun(SendAcc) -> SendFunResult, SendAcc} - HTLM-code
+%% {chunkify, fun(SendAcc) -> SendFunResult, SendAcc} - HTML-code
%% SendFunResult = eof | {ok, iolist(), NewSendAcc}
%% SendAcc = NewSendAcc = term()
%%
@@ -140,42 +143,31 @@ request(Url, Profile) ->
%% syncronus and asynchronous in the later case the function will
%% return {ok, RequestId} and later on a message will be sent to the
%% calling process on the format {http, {RequestId, {StatusLine,
-%% Headers, Body}}} or {http, {RequestId, {error, Reason}}}
+%% Headers, Body}}} or {http, {RequestId, {error, Reason}}}.
+%% Only octects are accepted in header fields and values.
%%--------------------------------------------------------------------------
request(Method, Request, HttpOptions, Options) ->
- request(Method, Request, HttpOptions, Options, default_profile()).
-
-request(Method,
- {Url, Headers, ContentType, TupleBody},
- HTTPOptions, Options, Profile)
- when ((Method =:= post) orelse (Method =:= patch) orelse (Method =:= put) orelse (Method =:= delete))
- andalso (is_atom(Profile) orelse is_pid(Profile)) andalso
- is_list(ContentType) andalso is_tuple(TupleBody)->
- case check_body_gen(TupleBody) of
- ok ->
- do_request(Method, {Url, Headers, ContentType, TupleBody}, HTTPOptions, Options, Profile);
- Error ->
- Error
- end;
-request(Method,
- {Url, Headers, ContentType, Body},
- HTTPOptions, Options, Profile)
- when ((Method =:= post) orelse (Method =:= patch) orelse (Method =:= put) orelse (Method =:= delete))
- andalso (is_atom(Profile) orelse is_pid(Profile)) andalso
- is_list(ContentType) andalso (is_list(Body) orelse is_binary(Body)) ->
- do_request(Method, {Url, Headers, ContentType, Body}, HTTPOptions, Options, Profile);
-
-request(Method,
- {Url, Headers},
- HTTPOptions, Options, Profile)
- when (Method =:= options) orelse
- (Method =:= get) orelse
- (Method =:= put) orelse
- (Method =:= head) orelse
- (Method =:= delete) orelse
- (Method =:= trace) andalso
- (is_atom(Profile) orelse is_pid(Profile)) ->
+ request(Method, Request, HttpOptions, Options, default_profile()).
+
+-define(WITH_BODY, [post, put, patch, delete]).
+-define(WITHOUT_BODY, [get, head, options, trace, put, delete]).
+
+request(Method, Request, HTTPOptions, Options, Profile)
+ when is_atom(Profile) orelse is_pid(Profile) ->
+ WithBody = lists:member(Method, ?WITH_BODY),
+ WithoutBody = lists:member(Method, ?WITHOUT_BODY),
+ case check_request(WithBody, WithoutBody, Request) of
+ ok ->
+ do_request(Method, Request,
+ HTTPOptions, Options, Profile);
+ {error, _} = Error ->
+ Error
+ end.
+
+do_request(Method, {Url, Headers}, HTTPOptions, Options, Profile) ->
+ do_request(Method, {Url, Headers, [], []}, HTTPOptions, Options, Profile);
+do_request(Method, {Url, Headers, ContentType, Body}, HTTPOptions, Options, Profile) ->
case normalize_and_parse_url(Url) of
{error, Reason, _} ->
{error, Reason};
@@ -183,21 +175,27 @@ request(Method,
case header_parse(Headers) of
{error, Reason} ->
{error, Reason};
- _ ->
- handle_request(Method, Url, ParsedUrl, Headers, [], [],
- HTTPOptions, Options, Profile)
- end
+ ok ->
+ handle_request(Method, Url,
+ ParsedUrl, Headers, ContentType, Body,
+ HTTPOptions, Options, Profile)
+ end
end.
-do_request(Method, {Url, Headers, ContentType, Body}, HTTPOptions, Options, Profile) ->
- case normalize_and_parse_url(Url) of
- {error, Reason, _} ->
- {error, Reason};
- ParsedUrl ->
- handle_request(Method, Url,
- ParsedUrl, Headers, ContentType, Body,
- HTTPOptions, Options, Profile)
- end.
+%% Check combination of method and presence of body
+check_request(false, false, _Request) ->
+ {error, invalid_method};
+check_request(_, true, {_URL, _Headers}) ->
+ ok;
+check_request(true, _, {_URL, _Headers, ContentType, Body})
+ when is_list(ContentType)
+ andalso (is_list(Body) orelse is_binary(Body)) ->
+ ok;
+check_request(true, _, {_URL, _Headers, ContentType, Body})
+ when is_list(ContentType) andalso is_tuple(Body) ->
+ check_body_gen(Body);
+check_request(_, _, _Request) ->
+ {error, invalid_request}.
%%--------------------------------------------------------------------------
%% cancel_request(RequestId) -> ok
@@ -1253,15 +1251,21 @@ validate_headers(RequestHeaders, _, _) ->
%%--------------------------------------------------------------------------
-%% These functions is just simple wrappers to parse specifically HTTP URIs
+%% These functions are just simple wrappers to parse specifically HTTP URIs
%%--------------------------------------------------------------------------
header_parse([]) ->
ok;
-header_parse([{Field, Value}|T]) when is_list(Field), is_list(Value) ->
+header_parse([{Field, Value}|T])
+ when is_list(Field)
+ andalso (is_list(Value) orelse is_binary(Value)) ->
header_parse(T);
-header_parse(_) ->
- {error, {headers_error, not_strings}}.
+header_parse([{Field, _Value}| _ ])
+ when not is_list(Field) ->
+ {error, {headers_error, invalid_field}};
+header_parse([{_, _}| _]) ->
+ {error, {headers_error, invalid_value}}.
+
child_name2info(undefined) ->
{error, no_such_service};
child_name2info(httpc_manager) ->
@@ -1277,9 +1281,9 @@ child_name(Pid, [_ | Children]) ->
child_name(Pid, Children).
-check_body_gen({Fun, _}) when is_function(Fun) ->
+check_body_gen({Fun, _}) when is_function(Fun, 1) ->
ok;
-check_body_gen({chunkify, Fun, _}) when is_function(Fun) ->
+check_body_gen({chunkify, Fun, _}) when is_function(Fun, 1) ->
ok;
-check_body_gen(Gen) ->
+check_body_gen(Gen) ->
{error, {bad_body_generator, Gen}}.
diff --git a/lib/inets/src/http_lib/http_request.erl b/lib/inets/src/http_lib/http_request.erl
index 2510cdede2..02fa8acb80 100644
--- a/lib/inets/src/http_lib/http_request.erl
+++ b/lib/inets/src/http_lib/http_request.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2021. 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.
@@ -201,107 +201,99 @@ headers(Key, Value, Headers) ->
Headers#http_request_h{other=
[{Key, Value} | Headers#http_request_h.other]}.
-key_value_str(Key = 'cache-control', Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.'cache-control');
-key_value_str(Key = connection, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.connection);
-key_value_str(Key = date, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.date);
-key_value_str(Key = pragma, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.pragma);
-key_value_str(Key = trailer, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.trailer);
-key_value_str(Key = 'transfer-encoding', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'transfer-encoding');
-key_value_str(Key = upgrade, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.upgrade);
-key_value_str(Key = via, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.via);
-key_value_str(Key = warning, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.warning);
-key_value_str(Key = accept, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.accept);
-key_value_str(Key = 'accept-charset', Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.'accept-charset');
-key_value_str(Key = 'accept-encoding', Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.'accept-encoding');
-key_value_str(Key = 'accept-language', Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.'accept-language');
-key_value_str(Key = authorization, Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.authorization);
-key_value_str(Key = expect, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.expect);
-key_value_str(Key = from, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.from);
-key_value_str(Key = host, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.host);
-key_value_str(Key = 'if-match', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'if-match');
-key_value_str(Key = 'if-modified-since', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'if-modified-since');
-key_value_str(Key = 'if-none-match', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'if-none-match');
-key_value_str(Key = 'if-range', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'if-range');
-key_value_str(Key = 'if-unmodified-since', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'if-unmodified-since');
-key_value_str(Key = 'max-forwards', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'max-forwards');
-key_value_str(Key = 'proxy-authorization', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'proxy-authorization');
-key_value_str(Key = range, Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.range);
-key_value_str(Key = referer, Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.referer);
-key_value_str(Key = te, Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.te);
-key_value_str(Key = 'user-agent', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'user-agent');
-key_value_str(Key = allow, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.allow);
-key_value_str(Key = 'content-encoding', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'content-encoding');
-key_value_str(Key = 'content-language', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'content-language');
-key_value_str(Key = 'content-length', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'content-length');
-key_value_str(Key = 'content-location', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'content-location');
-key_value_str(Key = 'content-md5', Headers) ->
- key_value_str(atom_to_list(Key),
- Headers#http_request_h.'content-md5');
-key_value_str(Key = 'content-range', Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.'content-range');
-key_value_str(Key = 'content-type', Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.'content-type');
-key_value_str(Key = expires, Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.expires);
-key_value_str(Key = 'last-modified', Headers) ->
- key_value_str(atom_to_list(Key), Headers#http_request_h.'last-modified');
-key_value_str(_, undefined) ->
- undefined;
-key_value_str(Key, Value) ->
- Key ++ ": " ++ Value ++ ?CRLF.
+key_value_str(Key, Headers) ->
+ case key_value(Key, Headers) of
+ undefined -> undefined;
+ Value ->
+ mk_key_value_str(atom_to_list(Key), Value)
+ end.
+
+key_value('cache-control', Headers) ->
+ Headers#http_request_h.'cache-control';
+key_value(connection, Headers) ->
+ Headers#http_request_h.connection;
+key_value(date, Headers) ->
+ Headers#http_request_h.date;
+key_value(pragma, Headers) ->
+ Headers#http_request_h.pragma;
+key_value(trailer, Headers) ->
+ Headers#http_request_h.trailer;
+key_value('transfer-encoding', Headers) ->
+ Headers#http_request_h.'transfer-encoding';
+key_value(upgrade, Headers) ->
+ Headers#http_request_h.upgrade;
+key_value(via, Headers) ->
+ Headers#http_request_h.via;
+key_value(warning, Headers) ->
+ Headers#http_request_h.warning;
+key_value(accept, Headers) ->
+ Headers#http_request_h.accept;
+key_value('accept-charset', Headers) ->
+ Headers#http_request_h.'accept-charset';
+key_value('accept-encoding', Headers) ->
+ Headers#http_request_h.'accept-encoding';
+key_value('accept-language', Headers) ->
+ Headers#http_request_h.'accept-language';
+key_value(authorization, Headers) ->
+ Headers#http_request_h.authorization;
+key_value(expect, Headers) ->
+ Headers#http_request_h.expect;
+key_value(from, Headers) ->
+ Headers#http_request_h.from;
+key_value(host, Headers) ->
+ Headers#http_request_h.host;
+key_value('if-match', Headers) ->
+ Headers#http_request_h.'if-match';
+key_value('if-modified-since', Headers) ->
+ Headers#http_request_h.'if-modified-since';
+key_value('if-none-match', Headers) ->
+ Headers#http_request_h.'if-none-match';
+key_value('if-range', Headers) ->
+ Headers#http_request_h.'if-range';
+key_value('if-unmodified-since', Headers) ->
+ Headers#http_request_h.'if-unmodified-since';
+key_value('max-forwards', Headers) ->
+ Headers#http_request_h.'max-forwards';
+key_value('proxy-authorization', Headers) ->
+ Headers#http_request_h.'proxy-authorization';
+key_value(range, Headers) ->
+ Headers#http_request_h.range;
+key_value(referer, Headers) ->
+ Headers#http_request_h.referer;
+key_value(te, Headers) ->
+ Headers#http_request_h.te;
+key_value('user-agent', Headers) ->
+ Headers#http_request_h.'user-agent';
+key_value(allow, Headers) ->
+ Headers#http_request_h.allow;
+key_value('content-encoding', Headers) ->
+ Headers#http_request_h.'content-encoding';
+key_value('content-language', Headers) ->
+ Headers#http_request_h.'content-language';
+key_value('content-length', Headers) ->
+ Headers#http_request_h.'content-length';
+key_value('content-location', Headers) ->
+ Headers#http_request_h.'content-location';
+key_value('content-md5', Headers) ->
+ Headers#http_request_h.'content-md5';
+key_value('content-range', Headers) ->
+ Headers#http_request_h.'content-range';
+key_value('content-type', Headers) ->
+ Headers#http_request_h.'content-type';
+key_value(expires, Headers) ->
+ Headers#http_request_h.expires;
+key_value('last-modified', Headers) ->
+ Headers#http_request_h.'last-modified'.
headers_other([], Headers) ->
Headers;
-headers_other([{Key,Value} | Rest], Headers) ->
- Header = Key ++ ": " ++ Value ++ ?CRLF,
- headers_other(Rest, [Header | Headers]).
+headers_other([{Key, Value} | Rest], Headers) ->
+ headers_other(Rest, [mk_key_value_str(Key, Value) | Headers]).
+
+mk_key_value_str(Key, Value) ->
+ Key ++ ": " ++ value_to_list(Value) ++ ?CRLF.
+
+value_to_list(Binary) when is_binary(Binary) ->
+ binary_to_list(Binary);
+value_to_list(List) when is_list(List) ->
+ binary_to_list(iolist_to_binary(List)).
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index b755c2ebef..f7eff5822d 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2021. 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.
@@ -98,6 +98,30 @@ real_requests()->
emulate_lower_versions,
headers,
headers_as_is,
+ header_type_0,
+ header_type_1,
+ header_type_2,
+ header_type_3,
+ header_type_4,
+ header_type_5,
+ header_type_6,
+ header_type_7,
+ header_type_8,
+ header_type_9,
+ header_type_10,
+ header_type_11,
+ header_type_12,
+ header_type_13,
+ header_type_14,
+ header_type_15,
+ header_type_16,
+ header_type_17,
+ header_type_18,
+ header_type_19,
+ header_type_20,
+ header_type_21,
+ header_type_22,
+ header_type_23,
empty_body,
stream,
stream_to_pid,
@@ -105,8 +129,11 @@ real_requests()->
stream_through_mfa,
streaming_error,
inet_opts,
- invalid_headers,
+ invalid_headers_key,
+ invalid_headers_value,
invalid_body,
+ invalid_body_fun,
+ invalid_method,
no_scheme,
invalid_uri,
undefined_port,
@@ -1217,23 +1244,106 @@ headers_conflict_chunked_with_length(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-invalid_headers(Config) ->
- Request = {url(group_name(Config), "/dummy.html", Config), [{"cookie", undefined}]},
- {error, _} = httpc:request(get, Request, [], []).
+
+invalid_headers_key(Config) ->
+ Request = {url(group_name(Config), "/dummy.html", Config),
+ [{cookie, "valid cookie"}]},
+ {error, {headers_error, invalid_field}} =
+ httpc:request(get, Request, [], []).
+
+invalid_headers_value(Config) ->
+ Request = {url(group_name(Config), "/dummy.html", Config),
+ [{"cookie", atom_value}]},
+ {error, {headers_error, invalid_value}} =
+ httpc:request(get, Request, [], []).
%%-------------------------------------------------------------------------
-invalid_body(Config) ->
+%% Doc not generated, but we can live without that. It should be
+%% [{doc, "Header type test"}].
+-define(HDR_TYPE_TEST(Name, Method, Value),
+ Name(Config) when is_list(Config) ->
+ test_header_type(Config, Method, Value)).
+
+?HDR_TYPE_TEST(header_type_0, get, "stringheader").
+?HDR_TYPE_TEST(header_type_1, get, <<"binary">>).
+?HDR_TYPE_TEST(header_type_2, get, ["an", <<"iolist">>]).
+?HDR_TYPE_TEST(header_type_3, head, "stringheader").
+?HDR_TYPE_TEST(header_type_4, head, <<"binary">>).
+?HDR_TYPE_TEST(header_type_5, head, ["an", <<"iolist">>]).
+?HDR_TYPE_TEST(header_type_6, post, "stringheader").
+?HDR_TYPE_TEST(header_type_7, post, <<"binary">>).
+?HDR_TYPE_TEST(header_type_8, post, ["an", <<"iolist">>]).
+?HDR_TYPE_TEST(header_type_9, put, "stringheader").
+?HDR_TYPE_TEST(header_type_10, put, <<"binary">>).
+?HDR_TYPE_TEST(header_type_11, put, ["an", <<"iolist">>]).
+?HDR_TYPE_TEST(header_type_12, delete, "stringheader").
+?HDR_TYPE_TEST(header_type_13, delete, <<"binary">>).
+?HDR_TYPE_TEST(header_type_14, delete, ["an", <<"iolist">>]).
+?HDR_TYPE_TEST(header_type_15, trace, "stringheader").
+?HDR_TYPE_TEST(header_type_16, trace, <<"binary">>).
+?HDR_TYPE_TEST(header_type_17, trace, ["an", <<"iolist">>]).
+?HDR_TYPE_TEST(header_type_18, patch, "stringheader").
+?HDR_TYPE_TEST(header_type_19, patch, <<"binary">>).
+?HDR_TYPE_TEST(header_type_20, patch, ["an", <<"iolist">>]).
+?HDR_TYPE_TEST(header_type_21, options, "stringheader").
+?HDR_TYPE_TEST(header_type_22, options, <<"binary">>).
+?HDR_TYPE_TEST(header_type_23, options, ["an", <<"iolist">>]).
+
+test_header_type(Config, Method, Value) ->
+ {Method, Value, {ok, _Data}} =
+ {Method, Value,
+ httpc:request(Method,
+ make_request(Config, Method, Value),
+ [],
+ [])}.
+
+make_request(Config, Method, Value) ->
URL = url(group_name(Config), "/dummy.html", Config),
- try
- httpc:request(post, {URL, [], <<"text/plain">>, "foobar"},
- [], []),
- ct:fail(accepted_invalid_input)
- catch
- error:function_clause ->
- ok
+ Headers = [{"other-header", Value},
+ {"user-agent", Value}],
+ %% Generate request with or without body, depending on method.
+ case method_type(Method) of
+ read ->
+ {URL, Headers};
+ write ->
+ {URL, Headers, "text/plain", ""}
end.
+method_type(Method) ->
+ case Method of
+ get -> read;
+ head -> read;
+ options -> read;
+ trace -> read;
+ post -> write;
+ put -> write;
+ delete -> write;
+ patch -> write
+ end.
+
+%%-------------------------------------------------------------------------
+
+invalid_body(Config) ->
+ URL = url(group_name(Config), "/dummy.html", Config),
+ {error, invalid_request} =
+ httpc:request(post, {URL, [], <<"text/plain">>, "foobar"},
+ [], []).
+
+invalid_body_fun(Config) ->
+ URL = url(group_name(Config), "/dummy.html", Config),
+ BodyFun = fun() -> body_part end,
+ {error, {bad_body_generator, _}} =
+ httpc:request(post, {URL, [], "text/plain", {BodyFun, init}},
+ [], []).
+
+
+invalid_method(Config) ->
+ URL = url(group_name(Config), "/dummy.html", Config),
+ {error, invalid_method} =
+ httpc:request(past, {URL, [], <<"text/plain">>, "foobar"},
+ [], []).
+
%%-------------------------------------------------------------------------
binary_url(Config) ->
@@ -1948,7 +2058,7 @@ setup_server_dirs(ServerRoot, DocRoot, DataDir) ->
"cgi_echo"
end,
- inets_test_lib:copy_file(Cgi, DataDir, CgiDir),
+ {ok, _} = inets_test_lib:copy_file(Cgi, DataDir, CgiDir),
AbsCgi = filename:join([CgiDir, Cgi]),
{ok, FileInfo} = file:read_file_info(AbsCgi),
ok = file:write_file_info(AbsCgi, FileInfo#file_info{mode = 8#00755}).
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 934f0629bf..fb348c06f3 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -31,6 +31,25 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 8.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> The undocumented DNS encode/decode module
+ <c>inet_dns</c> has been cleaned up to handle the
+ difference between "symbolic" and "raw" records in a more
+ consistent manner. </p><p> PR-5145/OTP-17584 introduced a
+ change that contributed to an already existing confusion,
+ which this correction should remedy. </p>
+ <p>
+ Own Id: OTP-17659 Aux Id: ERIERL-702 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 8.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index bbafb4f8fb..d05a2bb07e 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -50,7 +50,8 @@
{<<"^8\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^8\\.0\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^8\\.1$">>,[restart_new_emulator]},
- {<<"^8\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
+ {<<"^8\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^8\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
[{<<"^6\\.4$">>,[restart_new_emulator]},
{<<"^6\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^6\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -73,4 +74,5 @@
{<<"^8\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^8\\.0\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^8\\.1$">>,[restart_new_emulator]},
- {<<"^8\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
+ {<<"^8\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^8\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index b2d30db8a7..af7a614427 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 8.1.1
+KERNEL_VSN = 8.1.2
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index 7ad4acae51..beb1f0845a 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -35,6 +35,24 @@
<file>notes.xml</file>
</header>
+<section><title>Public_Key 1.11.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Avoid re-encoding of decoded certificates. This could
+ cause unexpected failures as some subtle encoding errors
+ can be tolerated when decoding but hence creating another
+ sequence of bytes if the decoded value is re-encoded.</p>
+ <p>
+ Own Id: OTP-17657</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Public_Key 1.11.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index a35a1c3906..262e927fce 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 1.11.2
+PUBLIC_KEY_VSN = 1.11.3
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 7d2c3e621a..7ca6cc2e5b 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -27,6 +27,46 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 10.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Before that change, TLS downgrade could occasionally fail
+ when data intended for downgraded socket were delivered
+ together with CLOSE_NOTIFY alert to ssl app.</p>
+ <p>
+ Own Id: OTP-17393</p>
+ </item>
+ <item>
+ <p>
+ Avoid re-encoding of decoded certificates. This could
+ cause unexpected failures as some subtle encoding errors
+ can be tolerated when decoding but hence creating another
+ sequence of bytes if the decoded value is re-encoded.</p>
+ <p>
+ Own Id: OTP-17657</p>
+ </item>
+ <item>
+ <p>
+ Fix possible process leak when the process doing
+ ssl:transport_accept dies before initiating the TLS
+ handshake.</p>
+ <p>
+ Own Id: OTP-17666 Aux Id: GH-5239 </p>
+ </item>
+ <item>
+ <p>
+ Fix dtls memory leak, the replay window code was broken.</p>
+ <p>
+ Own Id: OTP-17670 Aux Id: GH-5224 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 10.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssl/doc/src/standards_compliance.xml b/lib/ssl/doc/src/standards_compliance.xml
index cc74067ecf..3673372fdc 100644
--- a/lib/ssl/doc/src/standards_compliance.xml
+++ b/lib/ssl/doc/src/standards_compliance.xml
@@ -166,7 +166,7 @@
</cell>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>@OTP-16590@</em></cell>
+ <cell align="left" valign="middle"><em>24.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -178,7 +178,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">RSASSA-PSS signature schemes</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>@OTP-16590@</em></cell>
+ <cell align="left" valign="middle"><em>24.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -190,7 +190,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert extension</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>@OTP-16590@</em></cell>
+ <cell align="left" valign="middle"><em>24.1</em></cell>
</row>
<row>
diff --git a/lib/ssl/doc/src/using_ssl.xml b/lib/ssl/doc/src/using_ssl.xml
index fae2ca80e7..257f260d31 100644
--- a/lib/ssl/doc/src/using_ssl.xml
+++ b/lib/ssl/doc/src/using_ssl.xml
@@ -169,7 +169,7 @@ ok</code>
</code>
<p>In OTP 20 it is desirable to remove all cipher suites
- that uses rsa kexchange (removed from default in 21) </p>
+ that uses rsa key exchange (removed from default in 21) </p>
<code type="erl">2> NoRSA =
ssl:filter_cipher_suites(Default,
[{key_exchange, fun(rsa) -> false;
@@ -354,7 +354,7 @@ ok
<p>Step 3 - Explicit Session Reuse </p>
<code type="erl">
-%% Preform a full handshake and the session will not be saved for reuse
+%% Perform a full handshake and the session will not be saved for reuse
12&gt; {ok, C9} = ssl:connect("localhost", 9999, [{verify, verify_peer},
{versions, ['tlsv1.2']},
{cacertfile, "cacerts.pem"},
@@ -433,7 +433,7 @@ ok
<seeguide marker="ssl:using_ssl#anti-replay-protection-in-tls-1.3">
Anti-Replay Protection in TLS 1.3</seeguide>
</p>
- <p>Session tickets are sent by servers on newly estalished TLS connections.
+ <p>Session tickets are sent by servers on newly established TLS connections.
The number of tickets sent and their lifetime are configurable by application variables. See also
<seeapp marker="ssl:ssl_app#configuration"> SSL's configuration</seeapp>.</p>
<p>Session tickets are protected by application traffic keys, and in stateless
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index f325e71a11..d761520856 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -84,6 +84,6 @@
{applications, [crypto, public_key, kernel, stdlib]},
{env, []},
{mod, {ssl_app, []}},
- {runtime_dependencies, ["stdlib-3.12","public_key-@OTP-17657@","kernel-8.0",
+ {runtime_dependencies, ["stdlib-3.12","public_key-1.11.3","kernel-8.0",
"erts-10.0","crypto-5.0", "inets-5.10.7",
"runtime_tools-1.15.1"]}]}.
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index ebaa9a6bec..375a416b95 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -548,10 +548,10 @@ is_supported_signature_algorithm_1_2(#'OTPCertificate'{signatureAlgorithm =
is_supported_signature_algorithm_1_2(#'OTPCertificate'{signatureAlgorithm = SignAlg}, SignAlgs) ->
Scheme = ssl_cipher:signature_algorithm_to_scheme(SignAlg),
{Hash, Sign, _ } = ssl_cipher:scheme_to_components(Scheme),
- lists:member({pre_1_3_hash(Hash), pre_1_3_sign(Sign)}, SignAlgs).
+ ssl_cipher:is_supported_sign({pre_1_3_hash(Hash), pre_1_3_sign(Sign)}, ssl_cipher:signature_schemes_1_2(SignAlgs)).
is_supported_signature_algorithm_1_3(#'OTPCertificate'{signatureAlgorithm = SignAlg}, SignAlgs) ->
Scheme = ssl_cipher:signature_algorithm_to_scheme(SignAlg),
- lists:member(Scheme, SignAlgs).
+ ssl_cipher:is_supported_sign(Scheme, SignAlgs).
pre_1_3_sign(rsa_pkcs1) ->
rsa;
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 35b2da773b..63f46346ee 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -58,7 +58,9 @@
calc_mac_hash/4,
calc_mac_hash/6,
is_stream_ciphersuite/1,
+ is_supported_sign/2,
signature_scheme/1,
+ signature_schemes_1_2/1,
scheme_to_components/1,
hash_size/1,
effective_key_bits/1,
@@ -564,6 +566,93 @@ hash_size(sha384) ->
hash_size(sha512) ->
64.
+is_supported_sign({Hash, rsa} = SignAlgo, HashSigns) -> %% PRE TLS-1.3
+ lists:member(SignAlgo, HashSigns) orelse
+ lists:member({Hash, rsa_pss_rsae}, HashSigns);
+is_supported_sign(rsa_pkcs1_sha256 = SignAlgo, HashSigns) -> %% TLS-1.3 leagcy
+ lists:member(SignAlgo, HashSigns) orelse
+ lists:member(rsa_pss_rsae_sha256, HashSigns);
+is_supported_sign(rsa_pkcs1_sha384 = SignAlgo, HashSigns) -> %% TLS-1.3 leagcy
+ lists:member(SignAlgo, HashSigns) orelse
+ lists:member(rsa_pss_rsae_sha384, HashSigns);
+is_supported_sign(rsa_pkcs1_sha512 = SignAlgo, HashSigns) -> %% TLS-1.3 leagcy
+ lists:member(SignAlgo, HashSigns) orelse
+ lists:member(rsa_pss_rsae_sha512, HashSigns);
+is_supported_sign(SignAlgo, HashSigns) -> %% PRE TLS-1.3 SignAlgo::tuple() TLS-1.3 SignAlgo::atom()
+ lists:member(SignAlgo, HashSigns).
+
+signature_scheme(rsa_pkcs1_sha256) -> ?RSA_PKCS1_SHA256;
+signature_scheme(rsa_pkcs1_sha384) -> ?RSA_PKCS1_SHA384;
+signature_scheme(rsa_pkcs1_sha512) -> ?RSA_PKCS1_SHA512;
+signature_scheme(ecdsa_secp256r1_sha256) -> ?ECDSA_SECP256R1_SHA256;
+signature_scheme(ecdsa_secp384r1_sha384) -> ?ECDSA_SECP384R1_SHA384;
+signature_scheme(ecdsa_secp521r1_sha512) -> ?ECDSA_SECP521R1_SHA512;
+signature_scheme(rsa_pss_rsae_sha256) -> ?RSA_PSS_RSAE_SHA256;
+signature_scheme(rsa_pss_rsae_sha384) -> ?RSA_PSS_RSAE_SHA384;
+signature_scheme(rsa_pss_rsae_sha512) -> ?RSA_PSS_RSAE_SHA512;
+signature_scheme(eddsa_ed25519) -> ?ED25519;
+signature_scheme(eddsa_ed448) -> ?ED448;
+signature_scheme(rsa_pss_pss_sha256) -> ?RSA_PSS_PSS_SHA256;
+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;
+signature_scheme(?ECDSA_SECP256R1_SHA256) -> ecdsa_secp256r1_sha256;
+signature_scheme(?ECDSA_SECP384R1_SHA384) -> ecdsa_secp384r1_sha384;
+signature_scheme(?ECDSA_SECP521R1_SHA512) -> ecdsa_secp521r1_sha512;
+signature_scheme(?RSA_PSS_RSAE_SHA256) -> rsa_pss_rsae_sha256;
+signature_scheme(?RSA_PSS_RSAE_SHA384) -> rsa_pss_rsae_sha384;
+signature_scheme(?RSA_PSS_RSAE_SHA512) -> rsa_pss_rsae_sha512;
+signature_scheme(?ED25519) -> eddsa_ed25519;
+signature_scheme(?ED448) -> eddsa_ed448;
+signature_scheme(?RSA_PSS_PSS_SHA256) -> rsa_pss_pss_sha256;
+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 for logging purposes. These algorithms
+%% cannot be used in TLS 1.3 handshakes.
+signature_scheme(SignAlgo) when is_integer(SignAlgo) ->
+ <<?BYTE(Hash),?BYTE(Sign)>> = <<?UINT16(SignAlgo)>>,
+ {ssl_cipher:hash_algorithm(Hash), ssl_cipher:sign_algorithm(Sign)};
+signature_scheme(_) -> unassigned.
+
+signature_schemes_1_2(SigAlgs) ->
+ lists:map(fun(Algs) ->
+ {Hash, Sign, _} = scheme_to_components(Algs),
+ {Hash, Sign}
+ end, SigAlgs).
+
+%% TODO: reserved code points?
+
+scheme_to_components(rsa_pkcs1_sha256) -> {sha256, rsa_pkcs1, undefined};
+scheme_to_components(rsa_pkcs1_sha384) -> {sha384, rsa_pkcs1, undefined};
+scheme_to_components(rsa_pkcs1_sha512) -> {sha512, rsa_pkcs1, undefined};
+scheme_to_components(ecdsa_secp256r1_sha256) -> {sha256, ecdsa, secp256r1};
+scheme_to_components(ecdsa_secp384r1_sha384) -> {sha384, ecdsa, secp384r1};
+scheme_to_components(ecdsa_secp521r1_sha512) -> {sha512, ecdsa, secp521r1};
+scheme_to_components(rsa_pss_rsae_sha256) -> {sha256, rsa_pss_rsae, undefined};
+scheme_to_components(rsa_pss_rsae_sha384) -> {sha384, rsa_pss_rsae, undefined};
+scheme_to_components(rsa_pss_rsae_sha512) -> {sha512, rsa_pss_rsae, undefined};
+scheme_to_components(eddsa_ed25519) -> {none, eddsa, ed25519};
+scheme_to_components(eddsa_ed448) -> {none, eddsa, ed448};
+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};
+%% Handling legacy signature algorithms
+scheme_to_components({Hash,Sign}) -> {Hash, Sign, undefined}.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -752,71 +841,6 @@ sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 4) and (Other =<
sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 224) and (Other =< 255)) -> Other.
-signature_scheme(rsa_pkcs1_sha256) -> ?RSA_PKCS1_SHA256;
-signature_scheme(rsa_pkcs1_sha384) -> ?RSA_PKCS1_SHA384;
-signature_scheme(rsa_pkcs1_sha512) -> ?RSA_PKCS1_SHA512;
-signature_scheme(ecdsa_secp256r1_sha256) -> ?ECDSA_SECP256R1_SHA256;
-signature_scheme(ecdsa_secp384r1_sha384) -> ?ECDSA_SECP384R1_SHA384;
-signature_scheme(ecdsa_secp521r1_sha512) -> ?ECDSA_SECP521R1_SHA512;
-signature_scheme(rsa_pss_rsae_sha256) -> ?RSA_PSS_RSAE_SHA256;
-signature_scheme(rsa_pss_rsae_sha384) -> ?RSA_PSS_RSAE_SHA384;
-signature_scheme(rsa_pss_rsae_sha512) -> ?RSA_PSS_RSAE_SHA512;
-signature_scheme(eddsa_ed25519) -> ?ED25519;
-signature_scheme(eddsa_ed448) -> ?ED448;
-signature_scheme(rsa_pss_pss_sha256) -> ?RSA_PSS_PSS_SHA256;
-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;
-signature_scheme(?ECDSA_SECP256R1_SHA256) -> ecdsa_secp256r1_sha256;
-signature_scheme(?ECDSA_SECP384R1_SHA384) -> ecdsa_secp384r1_sha384;
-signature_scheme(?ECDSA_SECP521R1_SHA512) -> ecdsa_secp521r1_sha512;
-signature_scheme(?RSA_PSS_RSAE_SHA256) -> rsa_pss_rsae_sha256;
-signature_scheme(?RSA_PSS_RSAE_SHA384) -> rsa_pss_rsae_sha384;
-signature_scheme(?RSA_PSS_RSAE_SHA512) -> rsa_pss_rsae_sha512;
-signature_scheme(?ED25519) -> eddsa_ed25519;
-signature_scheme(?ED448) -> eddsa_ed448;
-signature_scheme(?RSA_PSS_PSS_SHA256) -> rsa_pss_pss_sha256;
-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 for logging purposes. These algorithms
-%% cannot be used in TLS 1.3 handshakes.
-signature_scheme(SignAlgo) when is_integer(SignAlgo) ->
- <<?BYTE(Hash),?BYTE(Sign)>> = <<?UINT16(SignAlgo)>>,
- {ssl_cipher:hash_algorithm(Hash), ssl_cipher:sign_algorithm(Sign)};
-signature_scheme(_) -> unassigned.
-%% TODO: reserved code points?
-
-scheme_to_components(rsa_pkcs1_sha256) -> {sha256, rsa_pkcs1, undefined};
-scheme_to_components(rsa_pkcs1_sha384) -> {sha384, rsa_pkcs1, undefined};
-scheme_to_components(rsa_pkcs1_sha512) -> {sha512, rsa_pkcs1, undefined};
-scheme_to_components(ecdsa_secp256r1_sha256) -> {sha256, ecdsa, secp256r1};
-scheme_to_components(ecdsa_secp384r1_sha384) -> {sha384, ecdsa, secp384r1};
-scheme_to_components(ecdsa_secp521r1_sha512) -> {sha512, ecdsa, secp521r1};
-scheme_to_components(rsa_pss_rsae_sha256) -> {sha256, rsa_pss_rsae, undefined};
-scheme_to_components(rsa_pss_rsae_sha384) -> {sha384, rsa_pss_rsae, undefined};
-scheme_to_components(rsa_pss_rsae_sha512) -> {sha512, rsa_pss_rsae, undefined};
-scheme_to_components(eddsa_ed25519) -> {none, eddsa, ed25519};
-scheme_to_components(eddsa_ed448) -> {none, eddsa, ed448};
-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};
-%% Handling legacy signature algorithms
-scheme_to_components({Hash,Sign}) -> {Hash, Sign, undefined}.
-
signature_algorithm_to_scheme(#'SignatureAlgorithm'{algorithm = ?'id-RSASSA-PSS',
parameters = #'RSASSA-PSS-params'{
maskGenAlgorithm =
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 63fbf5ffff..e7bbea3591 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -997,8 +997,15 @@ available_signature_algs(_, _) ->
available_signature_algs(undefined, SupportedHashSigns, _, Version) when
Version >= {3,3} ->
SupportedHashSigns;
-available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, SupportedHashSigns,
+available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, SupportedHashSigns0,
_, Version) when Version >= {3,3} ->
+ SupportedHashSigns =
+ case (Version == {3,3}) andalso contains_scheme(SupportedHashSigns0) of
+ true ->
+ ssl_cipher:signature_schemes_1_2(SupportedHashSigns0);
+ false ->
+ SupportedHashSigns0
+ end,
sets:to_list(sets:intersection(sets:from_list(ClientHashSigns),
sets:from_list(SupportedHashSigns)));
available_signature_algs(_, _, _, _) ->
@@ -3278,6 +3285,15 @@ filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], Has
%% In this case hashsigns is not used as the kexchange is anonaymous
filter_hashsigns(Suites, Algos, HashSigns, Version, [Suite| Acc]).
+do_filter_hashsigns(rsa = SignAlgo, Suite, Suites, Algos, HashSigns, {3,3} = Version, Acc) ->
+ case (lists:keymember(SignAlgo, 2, HashSigns) orelse
+ lists:keymember(rsa_pss_rsae, 2, HashSigns) orelse
+ lists:keymember(rsa_pss_pss, 2, HashSigns)) of
+ true ->
+ filter_hashsigns(Suites, Algos, HashSigns, Version, [Suite| Acc]);
+ false ->
+ filter_hashsigns(Suites, Algos, HashSigns, Version, Acc)
+ end;
do_filter_hashsigns(SignAlgo, Suite, Suites, Algos, HashSigns, Version, Acc) ->
case lists:keymember(SignAlgo, 2, HashSigns) of
true ->
@@ -3390,8 +3406,7 @@ is_acceptable_cert_type(Sign, Types) ->
%% signature_algorithms_cert = undefined
is_supported_sign(SignAlgo, _, HashSigns, []) ->
- lists:member(SignAlgo, HashSigns);
-
+ ssl_cipher:is_supported_sign(SignAlgo, HashSigns);
%% {'SignatureAlgorithm',{1,2,840,113549,1,1,11},'NULL'}
is_supported_sign({Hash, Sign}, 'NULL', _, SignatureSchemes) ->
Fun = fun (Scheme, Acc) ->
@@ -3408,7 +3423,6 @@ is_supported_sign({Hash, Sign}, 'NULL', _, SignatureSchemes) ->
Hash =:= H1)
end,
lists:foldl(Fun, false, SignatureSchemes);
-
%% TODO: Implement validation for the curve used in the signature
%% RFC 3279 - 2.2.3 ECDSA Signature Algorithm
%% When the ecdsa-with-SHA1 algorithm identifier appears as the
diff --git a/lib/ssl/test/openssl_client_cert_SUITE.erl b/lib/ssl/test/openssl_client_cert_SUITE.erl
index ad00f2da1f..c78bd9eadc 100644
--- a/lib/ssl/test/openssl_client_cert_SUITE.erl
+++ b/lib/ssl/test/openssl_client_cert_SUITE.erl
@@ -82,7 +82,7 @@ groups() ->
[
{openssl_client, [], protocol_groups()},
{'tlsv1.3', [], tls_1_3_protocol_groups()},
- {'tlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1.2', [], pre_tls_1_3_protocol_groups()}, %% Seems to be broken in OpenSSL [{group, rsa_pss_rsae}, {group, rsa_pss_pss}]},
{'tlsv1.1', [], pre_tls_1_3_protocol_groups()},
{'tlsv1', [], pre_tls_1_3_protocol_groups()},
{'dtlsv1.2', [], pre_tls_1_3_protocol_groups()},
@@ -92,8 +92,10 @@ groups() ->
{dsa, [], all_version_tests()},
{rsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++ [unsupported_sign_algo_client_auth,
unsupported_sign_algo_cert_client_auth]},
- {rsa_pss_rsae, [], all_version_tests() ++ tls_1_3_tests()},
+ {rsa_pss_rsae, [], all_version_tests()},
{rsa_pss_pss, [], all_version_tests() ++ tls_1_3_tests()},
+ {rsa_pss_rsae_1_3, [], all_version_tests() ++ tls_1_3_tests()},
+ {rsa_pss_pss_1_3, [], all_version_tests() ++ tls_1_3_tests()},
{ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()},
{eddsa_1_3, [], all_version_tests() ++ tls_1_3_tests()}
].
@@ -122,8 +124,8 @@ pre_tls_1_3_protocol_groups() ->
tls_1_3_protocol_groups() ->
[{group, rsa_1_3},
- {group, rsa_pss_rsae},
- {group, rsa_pss_pss},
+ {group, rsa_pss_rsae_1_3},
+ {group, rsa_pss_pss_1_3},
{group, ecdsa_1_3},
{group, eddsa_1_3}
].
@@ -198,23 +200,26 @@ init_per_group(Group, Config0) when Group == rsa;
[] ->
{skip, {no_sup, Group, Version}}
end;
-init_per_group(Alg, Config) when Alg == rsa_pss_rsae;
- Alg == rsa_pss_pss ->
+init_per_group(Alg, Config) when
+ Alg == rsa_pss_rsae;
+ Alg == rsa_pss_pss;
+ Alg == rsa_pss_rsae_1_3;
+ Alg == rsa_pss_pss_1_3 ->
Supports = crypto:supports(),
RSAOpts = proplists:get_value(rsa_opts, Supports),
case lists:member(rsa_pkcs1_pss_padding, RSAOpts)
andalso lists:member(rsa_pss_saltlen, RSAOpts)
andalso lists:member(rsa_mgf1_md, RSAOpts)
- andalso ssl_test_lib:is_sane_oppenssl_pss(Alg)
+ andalso ssl_test_lib:is_sane_oppenssl_pss(rsa_alg(Alg))
of
true ->
#{client_config := COpts,
- server_config := SOpts} = ssl_test_lib:make_rsa_pss_pem(Alg, [], Config, ""),
- [{cert_key_alg, Alg} |
+ server_config := SOpts} = ssl_test_lib:make_rsa_pss_pem(rsa_alg(Alg), [], Config, ""),
+ [{cert_key_alg, rsa_alg(Alg)} |
lists:delete(cert_key_alg,
- [{client_cert_opts, COpts},
- {server_cert_opts, SOpts} |
+ [{client_cert_opts, openssl_sig_algs(Alg) ++ COpts},
+ {server_cert_opts, sig_algs(rsa_alg(Alg)) ++ SOpts} |
lists:delete(server_cert_opts,
lists:delete(client_cert_opts, Config))])];
false ->
@@ -433,3 +438,28 @@ hello_retry_client_auth_empty_cert_rejected() ->
ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected().
hello_retry_client_auth_empty_cert_rejected(Config) ->
ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected(Config).
+
+rsa_alg(rsa_pss_rsae_1_3) ->
+ rsa_pss_rsae;
+rsa_alg(rsa_pss_pss_1_3) ->
+ rsa_pss_pss;
+rsa_alg(Atom) ->
+ Atom.
+
+sig_algs(rsa_pss_pss) ->
+ [{signature_algs, [rsa_pss_pss_sha512,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha256]}];
+sig_algs(rsa_pss_rsae) ->
+ [{signature_algs,[rsa_pss_rsae_sha512,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha256]}].
+
+openssl_sig_algs(rsa_pss_pss) ->
+ [{sigalgs, "rsa_pss_pss_sha256"}];
+openssl_sig_algs(rsa_pss_rsae) ->
+ [{sigalgs,"rsa_pss_rsae_sha256"}];
+openssl_sig_algs(rsa_pss_pss_1_3) ->
+ [{sigalgs, "rsa_pss_rsae_sha512:rsa_pss_rsae_sha384:rsa_pss_pss_sha256"}];
+openssl_sig_algs(rsa_pss_rsae_1_3) ->
+ [{sigalgs,"rsa_pss_rsae_sha512:rsa_pss_rsae_sha384:rsa_pss_rsae_sha256"}].
diff --git a/lib/ssl/test/ssl_cert_SUITE.erl b/lib/ssl/test/ssl_cert_SUITE.erl
index 42c44e4855..1eef4a48be 100644
--- a/lib/ssl/test/ssl_cert_SUITE.erl
+++ b/lib/ssl/test/ssl_cert_SUITE.erl
@@ -146,11 +146,11 @@ groups() ->
{'tlsv1', [], ssl_protocol_groups()},
{'dtlsv1.2', [], tls_1_2_protocol_groups()},
{'dtlsv1', [], ssl_protocol_groups()},
- {rsa, [], all_version_tests() ++ rsa_tests() ++ pre_tls_1_3_rsa_tests()},
+ {rsa, [], all_version_tests() ++ rsa_tests() ++ pre_tls_1_3_rsa_tests() ++ [client_auth_seelfsigned_peer]},
{ecdsa, [], all_version_tests()},
{dsa, [], all_version_tests()},
{rsa_1_3, [], all_version_tests() ++ rsa_tests() ++
- tls_1_3_tests() ++ tls_1_3_rsa_tests() ++ [basic_rsa_1024]},
+ tls_1_3_tests() ++ tls_1_3_rsa_tests() ++ [client_auth_seelfsigned_peer, basic_rsa_1024]},
{rsa_pss_rsae, [], all_version_tests() ++ tls_1_2_rsa_tests()},
{rsa_pss_rsae_1_3, [], all_version_tests() ++ rsa_tests() ++ tls_1_3_tests() ++ tls_1_3_rsa_tests()},
{rsa_pss_pss, [], all_version_tests()},
@@ -226,7 +226,6 @@ all_version_tests() ->
client_auth_do_not_allow_partial_chain,
client_auth_partial_chain_fun_fail,
client_auth_sni,
- client_auth_seelfsigned_peer,
missing_root_cert_no_auth,
missing_root_cert_auth,
missing_root_cert_auth_user_verify_fun_accept,
@@ -296,37 +295,9 @@ do_init_per_group(Alg, Config) when Alg == rsa_pss_rsae;
true ->
#{client_config := COpts,
server_config := SOpts} = ssl_test_lib:make_rsa_pss_pem(rsa_alg(Alg), [], Config, ""),
- [{cert_key_alg, rsa_alg(Alg)},
- {extra_client, [{signature_algs, [rsa_pss_pss_sha512,
- rsa_pss_pss_sha384,
- rsa_pss_pss_sha256,
- rsa_pss_rsae_sha512,
- rsa_pss_rsae_sha384,
- rsa_pss_rsae_sha256,
- rsa_pkcs1_sha512,
- rsa_pkcs1_sha384,
- rsa_pkcs1_sha256,
- rsa_pkcs1_sha1,
- {sha512, rsa},
- {sha384, rsa},
- {sha256, rsa},
- {sha224, rsa}
- ]}]},
- {extra_server, [{signature_algs, [rsa_pss_pss_sha512,
- rsa_pss_pss_sha384,
- rsa_pss_pss_sha256,
- rsa_pss_rsae_sha512,
- rsa_pss_rsae_sha384,
- rsa_pss_rsae_sha256,
- {sha512, ecdsa},
- {sha512, rsa},
- {sha384, ecdsa},
- {sha384, rsa},
- {sha256, ecdsa},
- {sha256, rsa},
- {sha224, ecdsa},
- {sha224, rsa}
- ]}]} |
+ [{cert_key_alg, Alg},
+ {extra_client, sig_algs(Alg)},
+ {extra_server, sig_algs(Alg)} |
lists:delete(cert_key_alg,
[{client_cert_opts, COpts},
{server_cert_opts, SOpts} |
@@ -1317,3 +1288,12 @@ chain_and_root(Config) ->
{ok, ExtractedCAs} = ssl_pkix_db:extract_trusted_certs({der, proplists:get_value(cacerts, Config)}),
{ok, Root, Chain} = ssl_certificate:certificate_chain(OwnCert, ets:new(foo, []), ExtractedCAs, [], encoded),
{Chain, Root}.
+
+sig_algs(rsa_pss_pss) ->
+ [{signature_algs, [rsa_pss_pss_sha512,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha256]}];
+sig_algs(rsa_pss_rsae) ->
+ [{signature_algs, [rsa_pss_rsae_sha512,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha256]}].
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index e4c23c22cf..183899e5f2 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -2080,6 +2080,7 @@ start_client(openssl, Port, ClientOpts, Config) ->
Ciphers = proplists:get_value(ciphers, ClientOpts, ssl:cipher_suites(default,Version)),
Groups0 = proplists:get_value(groups, ClientOpts),
CertArgs = openssl_cert_options(ClientOpts, client),
+ SigAlgs = openssl_sigalgs(proplists:get_value(sigalgs, ClientOpts, undefined)),
AlpnArgs = openssl_alpn_options(proplists:get_value(alpn, ClientOpts, undefined)),
NpnArgs = openssl_npn_options(proplists:get_value(np, ClientOpts, undefined)),
Reconnect = openssl_reconect_option(proplists:get_value(reconnect, ClientOpts, false)),
@@ -2096,7 +2097,7 @@ start_client(openssl, Port, ClientOpts, Config) ->
"-connect", hostname_format(HostName) ++ ":" ++ integer_to_list(Port), cipher_flag(Version),
ciphers(Ciphers, Version),
version_flag(Version)]
- ++ CertArgs ++ AlpnArgs ++ NpnArgs ++ Reconnect ++ MaxFragLen ++ SessionArgs
+ ++ CertArgs ++ SigAlgs ++ AlpnArgs ++ NpnArgs ++ Reconnect ++ MaxFragLen ++ SessionArgs
++ Debug;
Group ->
["s_client",
@@ -2104,7 +2105,7 @@ start_client(openssl, Port, ClientOpts, Config) ->
"-connect", hostname_format(HostName) ++ ":" ++ integer_to_list(Port), cipher_flag(Version),
ciphers(Ciphers, Version), "-groups", Group,
version_flag(Version)]
- ++ CertArgs ++ AlpnArgs ++ NpnArgs ++ Reconnect ++ MaxFragLen ++ SessionArgs
+ ++ CertArgs ++ SigAlgs ++ AlpnArgs ++ NpnArgs ++ Reconnect ++ MaxFragLen ++ SessionArgs
++ Debug
end,
Args = maybe_force_ipv4(Args0),
@@ -2347,6 +2348,11 @@ cert_option("-cert_chain", Value) ->
cert_option(Opt, Value) ->
[Opt, Value].
+openssl_sigalgs(undefined) ->
+ [];
+openssl_sigalgs(SigAlgs) ->
+ ["-sigalgs", SigAlgs].
+
supported_eccs(Opts) ->
ToCheck = proplists:get_value(eccs, Opts, []),
Supported = ssl:eccs(),
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index ada4a426a3..8f1847a5be 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 10.5
+SSL_VSN = 10.5.1
diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk
index a2ba51c9cf..f525368d7a 100644
--- a/make/otp_release_targets.mk
+++ b/make/otp_release_targets.mk
@@ -187,11 +187,15 @@ local_docs: local_copy_of_topdefs docs
local_html: TOPDOCDIR=.
local_html: local_copy_of_topdefs html
-local_copy_of_topdefs:
- $(INSTALL) $(DOCGEN)/priv/css/otp_doc.css $(HTMLDIR)
+$(HTMLDIR)/otp_doc.css:
+ ln -s $(DOCGEN)/priv/css/otp_doc.css $(HTMLDIR)/otp_doc.css
+
+local_copy_of_topdefs: $(HTMLDIR)/otp_doc.css
+ cd $(ERL_TOP) && make mod2app
$(INSTALL) $(DOCGEN)/priv/images/erlang-logo.png $(HTMLDIR)
$(INSTALL) $(DOCGEN)/priv/images/erlang-logo.gif $(HTMLDIR)
$(INSTALL_DIR) $(HTMLDIR)/js/flipmenu
+ $(INSTALL) $(DOCGEN)/priv/js/*.js $(HTMLDIR)/js
$(INSTALL) $(DOCGEN)/priv/js/flipmenu/flip_closed.gif \
$(DOCGEN)/priv/js/flipmenu/flip_open.gif \
$(DOCGEN)/priv/js/flipmenu/flip_static.gif \
diff --git a/make/otp_version_tickets_in_merge b/make/otp_version_tickets_in_merge
index 775591c8b2..553ca835d2 100644
--- a/make/otp_version_tickets_in_merge
+++ b/make/otp_version_tickets_in_merge
@@ -1,8 +1,8 @@
-OTP-17640
-OTP-17641
-OTP-17642
-OTP-17646
-OTP-17647
-OTP-17649
-OTP-17651
-OTP-17665
+OTP-17393
+OTP-17657
+OTP-17658
+OTP-17659
+OTP-17666
+OTP-17668
+OTP-17670
+OTP-17672
diff --git a/otp_versions.table b/otp_versions.table
index b1c033eb0d..54841f5bf3 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,3 +1,4 @@
+OTP-24.1.2 : crypto-5.0.4 erts-12.1.2 kernel-8.1.2 public_key-1.11.3 ssl-10.5.1 # asn1-5.0.17 common_test-1.21 compiler-8.0.3 debugger-5.2 dialyzer-4.4.2 diameter-2.2.4 edoc-1.0.1 eldap-1.2.9 erl_docgen-1.1.2 erl_interface-5.1 et-1.6.5 eunit-2.7 ftp-1.1 inets-7.4.2 jinterface-1.12.1 megaco-4.1 mnesia-4.20 observer-2.10 odbc-2.13.5 os_mon-2.7.1 parsetools-2.3.1 reltool-0.9 runtime_tools-1.17 sasl-4.1 snmp-5.10.1 ssh-4.12.4 stdlib-3.16.1 syntax_tools-2.6 tftp-1.0.3 tools-3.5.1 wx-2.1 xmerl-1.3.28 :
OTP-24.1.1 : erts-12.1.1 kernel-8.1.1 snmp-5.10.1 stdlib-3.16.1 # asn1-5.0.17 common_test-1.21 compiler-8.0.3 crypto-5.0.3 debugger-5.2 dialyzer-4.4.2 diameter-2.2.4 edoc-1.0.1 eldap-1.2.9 erl_docgen-1.1.2 erl_interface-5.1 et-1.6.5 eunit-2.7 ftp-1.1 inets-7.4.2 jinterface-1.12.1 megaco-4.1 mnesia-4.20 observer-2.10 odbc-2.13.5 os_mon-2.7.1 parsetools-2.3.1 public_key-1.11.2 reltool-0.9 runtime_tools-1.17 sasl-4.1 ssh-4.12.4 ssl-10.5 syntax_tools-2.6 tftp-1.0.3 tools-3.5.1 wx-2.1 xmerl-1.3.28 :
OTP-24.1 : asn1-5.0.17 common_test-1.21 compiler-8.0.3 crypto-5.0.3 debugger-5.2 dialyzer-4.4.2 edoc-1.0.1 erl_docgen-1.1.2 erl_interface-5.1 erts-12.1 eunit-2.7 inets-7.4.2 jinterface-1.12.1 kernel-8.1 megaco-4.1 mnesia-4.20 observer-2.10 os_mon-2.7.1 parsetools-2.3.1 public_key-1.11.2 runtime_tools-1.17 snmp-5.10 ssh-4.12.4 ssl-10.5 stdlib-3.16 tools-3.5.1 wx-2.1 # diameter-2.2.4 eldap-1.2.9 et-1.6.5 ftp-1.1 odbc-2.13.5 reltool-0.9 sasl-4.1 syntax_tools-2.6 tftp-1.0.3 xmerl-1.3.28 :
OTP-24.0.6 : erts-12.0.4 # asn1-5.0.16 common_test-1.20.5 compiler-8.0.2 crypto-5.0.2 debugger-5.1 dialyzer-4.4.1 diameter-2.2.4 edoc-1.0 eldap-1.2.9 erl_docgen-1.1.1 erl_interface-5.0.1 et-1.6.5 eunit-2.6.1 ftp-1.1 inets-7.4.1 jinterface-1.12 kernel-8.0.2 megaco-4.0.1 mnesia-4.19.1 observer-2.9.6 odbc-2.13.5 os_mon-2.7 parsetools-2.3 public_key-1.11.1 reltool-0.9 runtime_tools-1.16.2 sasl-4.1 snmp-5.9.1 ssh-4.12.3 ssl-10.4.2 stdlib-3.15.2 syntax_tools-2.6 tftp-1.0.3 tools-3.5 wx-2.0.1 xmerl-1.3.28 :
diff --git a/scripts/otp_html_check b/scripts/otp_html_check
index 893d2b55f1..3606ed22d4 100755
--- a/scripts/otp_html_check
+++ b/scripts/otp_html_check
@@ -226,7 +226,7 @@ sub get_page_links {
($html =~ m/
<
\s*
- A
+ (?: A|H[1-6])
[^>]*
\s (?: NAME|ID) \s* = \s*
(?: \"([^\"]*)\" | \'([^\']*)\' | ([^>\s]+) )
diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile
index 3ebee96c08..803f907994 100644
--- a/system/doc/top/Makefile
+++ b/system/doc/top/Makefile
@@ -260,9 +260,9 @@ $(TOP_PDF_FILE): $(XML_FILES)
pdf: $(TOP_PDF_FILE)
-html: $(INDEX_FILES) $(JAVASCRIPT)
+html: $(INDEX_FILES) $(JAVASCRIPT) $(MAN_INDEX)
-man: $(MAN_INDEX)
+man:
debug opt:
@@ -287,10 +287,10 @@ $(RELSYSDIR)/docbuild:
$(INSTALL_DIR) $(RELSYSDIR)/docbuild
release_man_spec: man $(RELSYSDIR)/docbuild
- $(INSTALL_DATA) $(MAN_INDEX) $(RELSYSDIR)
- $(INSTALL_DATA) $(MAN_INDEX_SRC) $(MAN_INDEX_SCRIPT) $(RELSYSDIR)/docbuild
release_html_spec: html $(RELSYSDIR)/docbuild
+ $(INSTALL_DATA) $(MAN_INDEX) $(RELSYSDIR)
+ $(INSTALL_DATA) $(MAN_INDEX_SRC) $(MAN_INDEX_SCRIPT) $(RELSYSDIR)/docbuild
$(INSTALL_DIR) $(RELSYSDIR)/js
$(INSTALL_DATA) $(JAVASCRIPT) $(RELSYSDIR)/js
$(INSTALL_DATA) $(INDEX_FILES) $(RELSYSDIR)
diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src
index ec53a5b3c5..0c899efe0c 100644
--- a/system/doc/top/templates/index.html.src
+++ b/system/doc/top/templates/index.html.src
@@ -20,20 +20,45 @@ limitations under the License.
-->
<html>
-<head>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1"></meta>
+ <meta charset="utf-8"></meta>
<link rel="stylesheet" href="otp_doc.css" type="text/css"/>
<title>Erlang/OTP #otp_base_vsn#</title>
<script id="js" type="text/javascript" language="JavaScript" src="js/flipmenu/flipmenu.js">
-
+</script>
+<script id="js2" type="text/javascript" language="JavaScript" src="js/topbar.js">
</script>
</head>
<body>
-
-<div id="container">
-<div id="leftnav">
-<div class="leftnav-tube">
+ <div id="container">
+ <div class="topbar">
+ <div class="topbar-expand">
+ <button onclick="toggleDisplay();">
+ <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54" width="24" height="24">
+<g>
+ <path style="fill:#000000;" d="M27,54c-0.552,0-1-0.448-1-1V8c0-0.552,0.448-1,1-1s1,0.448,1,1v45C28,53.552,27.552,54,27,54z"/>
+ <path style="fill:#000000;" d="M11,25c-0.256,0-0.512-0.098-0.707-0.293c-0.391-0.391-0.391-1.023,0-1.414l16-16
+ c0.391-0.391,1.023-0.391,1.414,0s0.391,1.023,0,1.414l-16,16C11.512,24.902,11.256,25,11,25z"/>
+ <path style="fill:#000000;" d="M43,25c-0.256,0-0.512-0.098-0.707-0.293l-16-16c-0.391-0.391-0.391-1.023,0-1.414
+ s1.023-0.391,1.414,0l16,16c0.391,0.391,0.391,1.023,0,1.414C43.512,24.902,43.256,25,43,25z"/>
+ <path style="fill:#000000;" d="M43,2H11c-0.552,0-1-0.448-1-1s0.448-1,1-1h32c0.552,0,1,0.448,1,1S43.552,2,43,2z"/>
+</g>
+ </svg>
+ </button>
+ </div>
+ <div class="topbar-title">
+ <h1>
+ Erlang/OTP #otp_base_vsn#
+ </h1>
+ </div>
+ <div class="search-expand">
+ </div>
+ </div>
+<aside id="leftnav">
+<nav class="leftnav-tube">
<div class="erlang-logo-wrapper">
<img alt="Erlang logo" src="erlang-logo.png" class="erlang-logo"/ >
</div>
@@ -78,8 +103,8 @@ limitations under the License.
#applinks#
</ul>
-</div>
-</div>
+</nav>
+</aside>
<div id="content">
@@ -92,7 +117,18 @@ limitations under the License.
<h2>Some hints that may get you started faster</h2>
<ul>
-
+ <li class="mobile-only">
+ The navigation menu can be accessed by clicking the <svg style="transform: rotate(180deg);" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54" width="24" height="24">
+<g>
+ <path style="fill:#000000;" d="M27,54c-0.552,0-1-0.448-1-1V8c0-0.552,0.448-1,1-1s1,0.448,1,1v45C28,53.552,27.552,54,27,54z"/>
+ <path style="fill:#000000;" d="M11,25c-0.256,0-0.512-0.098-0.707-0.293c-0.391-0.391-0.391-1.023,0-1.414l16-16
+ c0.391-0.391,1.023-0.391,1.414,0s0.391,1.023,0,1.414l-16,16C11.512,24.902,11.256,25,11,25z"/>
+ <path style="fill:#000000;" d="M43,25c-0.256,0-0.512-0.098-0.707-0.293l-16-16c-0.391-0.391-0.391-1.023,0-1.414
+ s1.023-0.391,1.414,0l16,16c0.391,0.391,0.391,1.023,0,1.414C43.512,24.902,43.256,25,43,25z"/>
+ <path style="fill:#000000;" d="M43,2H11c-0.552,0-1-0.448-1-1s0.448-1,1-1h32c0.552,0,1,0.448,1,1S43.552,2,43,2z"/>
+</g>
+ </svg> symbol in the top left corner.
+ </li>
<li>
The Erlang language is described in the
<a href="reference_manual/users_guide.html">Erlang Reference Manual</a>.