aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorIngela Anderton Andin <[email protected]>2017-04-04 16:25:39 +0200
committerIngela Anderton Andin <[email protected]>2017-04-04 16:25:39 +0200
commitc04e4cd533d9a4185eadda3141e0783b0f5a0fae (patch)
treefe4796bf3371069132cf591b7524ba48adf6a4cf /lib
parent38cd77b3e7afbf3973167c5a339381707e3d95bc (diff)
parentd25ad84195ca42969fbfb017a52aab8c8effc246 (diff)
downloadotp-c04e4cd533d9a4185eadda3141e0783b0f5a0fae.tar.gz
otp-c04e4cd533d9a4185eadda3141e0783b0f5a0fae.tar.bz2
otp-c04e4cd533d9a4185eadda3141e0783b0f5a0fae.zip
Merge branch 'maint-19' into maint
Diffstat (limited to 'lib')
-rw-r--r--lib/crypto/c_src/crypto.c36
-rw-r--r--lib/crypto/doc/src/notes.xml16
-rw-r--r--lib/crypto/src/crypto.erl6
-rw-r--r--lib/crypto/test/crypto_SUITE.erl10
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/inets/doc/src/notes.xml18
-rw-r--r--lib/inets/src/ftp/ftp.erl28
-rw-r--r--lib/inets/src/http_client/httpc.erl10
-rw-r--r--lib/inets/src/http_client/httpc_response.erl3
-rw-r--r--lib/inets/src/http_lib/http_request.erl18
-rw-r--r--lib/inets/test/ftp_SUITE.erl54
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/ssh/doc/src/notes.xml16
-rw-r--r--lib/ssh/src/ssh.erl2
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/src/notes.xml18
-rw-r--r--lib/ssl/src/ssl.appup.src2
-rw-r--r--lib/ssl/src/tls_connection.erl37
-rw-r--r--lib/ssl/vsn.mk2
19 files changed, 236 insertions, 46 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 2c8fb445dd..d4264335b6 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -231,6 +231,7 @@ static ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
static ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -301,6 +302,7 @@ static ErlNifFunc nif_funcs[] = {
{"hmac_final_nif", 2, hmac_final_nif},
{"block_crypt_nif", 5, block_crypt_nif},
{"block_crypt_nif", 4, block_crypt_nif},
+ {"aes_cfb_128_crypt_nif", 4, aes_cfb_128_crypt_nif},
{"aes_ige_crypt_nif", 4, aes_ige_crypt_nif},
{"aes_ctr_encrypt", 3, aes_ctr_encrypt},
@@ -1403,13 +1405,20 @@ static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
return enif_raise_exception(env, atom_notsup);
}
- if ((argv[0] == atom_aes_cfb8 || argv[0] == atom_aes_cfb128)
+ if (argv[0] == atom_aes_cfb8
&& (key.size == 24 || key.size == 32)) {
/* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
* Fall back on low level API
*/
return aes_cfb_8_crypt(env, argc-1, argv+1);
}
+ else if (argv[0] == atom_aes_cfb128
+ && (key.size == 24 || key.size == 32)) {
+ /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
+ * Fall back on low level API
+ */
+ return aes_cfb_128_crypt_nif(env, argc-1, argv+1);
+ }
ivec_size = EVP_CIPHER_iv_length(cipher);
@@ -1483,6 +1492,31 @@ static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
return ret;
}
+static ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IVec, Data, IsEncrypt) */
+ ErlNifBinary key, ivec, text;
+ AES_KEY aes_key;
+ unsigned char ivec_clone[16]; /* writable copy */
+ int new_ivlen = 0;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
+ || !(key.size == 16 || key.size == 24 || key.size == 32)
+ || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
+ || !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
+ return enif_make_badarg(env);
+ }
+
+ memcpy(ivec_clone, ivec.data, 16);
+ AES_set_encrypt_key(key.data, key.size * 8, &aes_key);
+ AES_cfb128_encrypt((unsigned char *) text.data,
+ enif_make_new_binary(env, text.size, &ret),
+ text.size, &aes_key, ivec_clone, &new_ivlen,
+ (argv[3] != atom_true));
+ CONSUME_REDS(env,text);
+ return ret;
+}
+
static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IVec, Data, IsEncrypt) */
#ifdef HAVE_AES_IGE
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 37997b649b..887aeca680 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,22 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 3.7.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix a bug with AES CFB 128 for 192 and 256 bit keys.
+ Thanks to kellymclaughlin !</p>
+ <p>
+ Own Id: OTP-14313 Aux Id: PR-1393 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 3.7.3</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 696929ba4e..60e0affda0 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -822,6 +822,8 @@ sha_mac_96(Key, Data) -> hmac(sha, Key, Data, 12).
block_crypt_nif(_Type, _Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub.
block_crypt_nif(_Type, _Key, _Text, _IsEncrypt) -> ?nif_stub.
+aes_cfb_128_crypt_nif(_Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub.
+
check_des3_key(Key) ->
case lists:map(fun erlang:iolist_to_binary/1, Key) of
ValidKey = [B1, B2, B3] when byte_size(B1) =:= 8,
@@ -915,7 +917,9 @@ blowfish_ofb64_encrypt(Key, IVec, Data) ->
-spec aes_cfb_128_decrypt(iodata(), binary(), iodata()) -> binary().
aes_cfb_128_encrypt(Key, IVec, Data) ->
- block_encrypt(aes_cfb128, Key, IVec, Data).
+ %% block_encrypt(aes_cfb128, Key, IVec, Data).
+ aes_cfb_128_crypt_nif(Key, IVec, Data, true).
+
aes_cfb_128_decrypt(Key, IVec, Data) ->
block_decrypt(aes_cfb128, Key, IVec, Data).
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 7b07cef33f..dbd335c693 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -358,6 +358,16 @@ block_cipher({Type, Key, PlainText}) ->
ct:fail({{crypto, block_decrypt, [Type, Key, CipherText]}, {expected, Plain}, {got, Other}})
end;
+block_cipher({aes_cfb128, Key, IV, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ CipherText = crypto:aes_cfb_128_encrypt(Key, IV, PlainText),
+ case crypto:block_decrypt(aes_cfb128, Key, IV, CipherText) of
+ Plain ->
+ ok;
+ Other ->
+ ct:fail({{crypto, block_decrypt, [aes_cfb128, Key, IV, CipherText]}, {expected, Plain}, {got, Other}})
+ end;
+
block_cipher({Type, Key, IV, PlainText}) ->
Plain = iolist_to_binary(PlainText),
CipherText = crypto:block_encrypt(Type, Key, IV, PlainText),
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 81cb2f8130..f3e0623ac9 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 3.7.3
+CRYPTO_VSN = 3.7.4
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index e102ad4826..ea600581ff 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -33,7 +33,23 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 6.3.6</title>
+ <section><title>Inets 6.3.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a bug in ftp that made further operations after a
+ recv_chunk operation impossible.</p>
+ <p>
+ Own Id: OTP-14242</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index 9d0c59eda8..2a225e930e 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -108,7 +108,7 @@
-define(DBG(F,A), 'n/a').
%%-define(DBG(F,A), io:format(F,A)).
-%%-define(DBG(F,A), if is_list(F) -> ct:pal(F,A); is_atom(F)->ct:pal(atom_to_list(F),A) end).
+%%-define(DBG(F,A), ct:pal("~p:~p " ++ if is_list(F) -> F; is_atom(F) -> atom_to_list(F) end, [?MODULE,?LINE|A])).
%%%=========================================================================
%%% API - CLIENT FUNCTIONS
@@ -1482,13 +1482,13 @@ handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
activate_ctrl_connection(State),
{noreply, State#state{dsock = undefined, data = <<>>}};
-handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, client = From,
+handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
caller = recv_chunk} = State)
when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
- gen_server:reply(From, ok),
- {noreply, State#state{dsock = undefined, client = undefined,
- data = <<>>, caller = undefined,
- chunk = false}};
+ activate_ctrl_connection(State),
+ {noreply, State#state{dsock = undefined, data = <<>>,
+ caller = recv_chunk_closed
+ }};
handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, caller = recv_bin,
data = Data} = State)
@@ -1601,13 +1601,13 @@ terminate(normal, State) ->
%% If terminate reason =/= normal the progress reporting process will
%% be killed by the exit signal.
progress_report(stop, State),
- do_termiante({error, econn}, State);
+ do_terminate({error, econn}, State);
terminate(Reason, State) ->
Report = io_lib:format("Ftp connection closed due to: ~p~n", [Reason]),
error_logger:error_report(Report),
- do_termiante({error, eclosed}, State).
+ do_terminate({error, eclosed}, State).
-do_termiante(ErrorMsg, State) ->
+do_terminate(ErrorMsg, State) ->
close_data_connection(State),
close_ctrl_connection(State),
case State#state.client of
@@ -2046,6 +2046,16 @@ handle_ctrl_result({pos_prel, _}, #state{client = From,
end;
%%--------------------------------------------------------------------------
+%% File handling - chunk_transfer complete
+handle_ctrl_result({pos_compl, _}, #state{client = From,
+ caller = recv_chunk_closed}
+ = State0) ->
+ gen_server:reply(From, ok),
+ {noreply, State0#state{caller = undefined,
+ chunk = false,
+ client = undefined}};
+
+%%--------------------------------------------------------------------------
%% File handling - recv_file
handle_ctrl_result({pos_prel, _}, #state{caller = {recv_file, _}} = State0) ->
case accept_data_connection(State0) of
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index bd5f6df39e..418b6247b0 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -524,7 +524,7 @@ handle_request(Method, Url,
Options = request_options(Options0),
Sync = proplists:get_value(sync, Options),
Stream = proplists:get_value(stream, Options),
- Host2 = header_host(Scheme, Host, Port),
+ Host2 = http_request:normalize_host(Scheme, Host, Port),
HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions),
Receiver = proplists:get_value(receiver, Options),
SocketOpts = proplists:get_value(socket_opts, Options),
@@ -1035,14 +1035,6 @@ bad_option(Option, BadValue) ->
throw({error, {bad_option, Option, BadValue}}).
-header_host(https, Host, 443 = _Port) ->
- Host;
-header_host(http, Host, 80 = _Port) ->
- Host;
-header_host(_Scheme, Host, Port) ->
- Host ++ ":" ++ integer_to_list(Port).
-
-
header_record(NewHeaders, Host, #http_options{version = Version}) ->
header_record(NewHeaders, #http_request_h{}, Host, Version).
diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl
index 0fd5faa466..5fbceb8ad0 100644
--- a/lib/inets/src/http_client/httpc_response.erl
+++ b/lib/inets/src/http_client/httpc_response.erl
@@ -362,8 +362,9 @@ redirect(Response = {StatusLine, Headers, Body}, Request) ->
{ok, error(Request, Reason), Data};
%% Automatic redirection
{ok, {Scheme, _, Host, Port, Path, Query}} ->
+ HostPort = http_request:normalize_host(Scheme, Host, Port),
NewHeaders =
- (Request#request.headers)#http_request_h{host = Host++":"++integer_to_list(Port)},
+ (Request#request.headers)#http_request_h{host = HostPort},
NewRequest =
Request#request{redircount =
Request#request.redircount+1,
diff --git a/lib/inets/src/http_lib/http_request.erl b/lib/inets/src/http_lib/http_request.erl
index c77b616f0d..4c50edb5ef 100644
--- a/lib/inets/src/http_lib/http_request.erl
+++ b/lib/inets/src/http_lib/http_request.erl
@@ -22,7 +22,7 @@
-include("http_internal.hrl").
--export([headers/2, http_headers/1, is_absolut_uri/1, key_value/1]).
+-export([headers/2, http_headers/1, is_absolut_uri/1, key_value/1, normalize_host/3]).
key_value(KeyValueStr) ->
@@ -85,6 +85,22 @@ is_absolut_uri("https://" ++ _) ->
is_absolut_uri(_) ->
false.
+%%-------------------------------------------------------------------------
+%% normalize_host(Scheme, Host, Port) -> string()
+%% Scheme - http | https
+%% Host - string()
+%% Port - integer()
+%%
+%% Description: returns a normalized Host header value, with the port
+%% number omitted for well-known ports
+%%-------------------------------------------------------------------------
+normalize_host(https, Host, 443 = _Port) ->
+ Host;
+normalize_host(http, Host, 80 = _Port) ->
+ Host;
+normalize_host(_Scheme, Host, Port) ->
+ Host ++ ":" ++ integer_to_list(Port).
+
%%%========================================================================
%%% Internal functions
%%%========================================================================
diff --git a/lib/inets/test/ftp_SUITE.erl b/lib/inets/test/ftp_SUITE.erl
index e2dec0c42a..d37f2feb7e 100644
--- a/lib/inets/test/ftp_SUITE.erl
+++ b/lib/inets/test/ftp_SUITE.erl
@@ -93,8 +93,10 @@ ftp_tests()->
append_chunk,
recv,
recv_3,
- recv_bin,
+ recv_bin,
+ recv_bin_twice,
recv_chunk,
+ recv_chunk_twice,
type,
quote,
error_elogin,
@@ -533,15 +535,19 @@ append_chunk(Config0) ->
recv() ->
[{doc, "Receive a file using recv/2"}].
recv(Config0) ->
- File = "f_dst.txt",
+ File1 = "f_dst1.txt",
+ File2 = "f_dst2.txt",
SrcDir = "a_dir",
- Contents = <<"ftp_SUITE test ...">>,
- Config = set_state([reset, {mkfile,[SrcDir,File],Contents}], Config0),
+ Contents1 = <<"1 ftp_SUITE test ...">>,
+ Contents2 = <<"2 ftp_SUITE test ...">>,
+ Config = set_state([reset, {mkfile,[SrcDir,File1],Contents1}, {mkfile,[SrcDir,File2],Contents2}], Config0),
Pid = proplists:get_value(ftp, Config),
ok = ftp:cd(Pid, id2ftp(SrcDir,Config)),
ok = ftp:lcd(Pid, id2ftp("",Config)),
- ok = ftp:recv(Pid, File),
- chk_file(File, Contents, Config),
+ ok = ftp:recv(Pid, File1),
+ chk_file(File1, Contents1, Config),
+ ok = ftp:recv(Pid, File2),
+ chk_file(File2, Contents2, Config),
{error,epath} = ftp:recv(Pid, "non_existing_file"),
ok.
@@ -572,6 +578,25 @@ recv_bin(Config0) ->
ok.
%%-------------------------------------------------------------------------
+recv_bin_twice() ->
+ [{doc, "Receive two files as a binaries."}].
+recv_bin_twice(Config0) ->
+ File1 = "f_dst1.txt",
+ File2 = "f_dst2.txt",
+ Contents1 = <<"1 ftp_SUITE test ...">>,
+ Contents2 = <<"2 ftp_SUITE test ...">>,
+ Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0),
+ ct:log("First transfer",[]),
+ Pid = proplists:get_value(ftp, Config),
+ {ok,Received1} = ftp:recv_bin(Pid, id2ftp(File1,Config)),
+ find_diff(Received1, Contents1),
+ ct:log("Second transfer",[]),
+ {ok,Received2} = ftp:recv_bin(Pid, id2ftp(File2,Config)),
+ find_diff(Received2, Contents2),
+ ct:log("Transfers ready!",[]),
+ {error,epath} = ftp:recv_bin(Pid, id2ftp("non_existing_file",Config)),
+ ok.
+%%-------------------------------------------------------------------------
recv_chunk() ->
[{doc, "Receive a file using chunk-wise."}].
recv_chunk(Config0) ->
@@ -584,6 +609,23 @@ recv_chunk(Config0) ->
{ok, ReceivedContents, _Ncunks} = recv_chunk(Pid, <<>>),
find_diff(ReceivedContents, Contents).
+recv_chunk_twice() ->
+ [{doc, "Receive two files using chunk-wise."}].
+recv_chunk_twice(Config0) ->
+ File1 = "big_file1.txt",
+ File2 = "big_file2.txt",
+ Contents1 = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ),
+ Contents2 = crypto:strong_rand_bytes(1200),
+ Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {{error, "ftp:recv_chunk_start/2 not called"},_} = recv_chunk(Pid, <<>>),
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)),
+ {ok, ReceivedContents1, _Ncunks1} = recv_chunk(Pid, <<>>),
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File2,Config)),
+ {ok, ReceivedContents2, _Ncunks2} = recv_chunk(Pid, <<>>),
+ find_diff(ReceivedContents1, Contents1),
+ find_diff(ReceivedContents2, Contents2).
+
recv_chunk(Pid, Acc) ->
recv_chunk(Pid, Acc, 0).
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index f2288466f8..b0b39b54c5 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 6.3.6
+INETS_VSN = 6.3.7
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 02a39f030c..c8c6e61cc8 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,22 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.4.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ ssh:daemon_info/1 crashed if the listening IP was not
+ 'any'</p>
+ <p>
+ Own Id: OTP-14298 Aux Id: seq13294 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.4.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 1f3f77a4e4..290525cec0 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -175,7 +175,7 @@ daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
AsupPid when is_pid(AsupPid) ->
[Port] =
- [Prt || {{ssh_acceptor_sup,any,Prt,default},
+ [Prt || {{ssh_acceptor_sup,_,Prt,_},
_WorkerPid,worker,[ssh_acceptor]} <- supervisor:which_children(AsupPid)],
{ok, [{port,Port}]};
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 96c83cb0f7..48332d2e5a 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.4.1
+SSH_VSN = 4.4.2
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index d3ab3e9216..7ffb9c0e88 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -28,6 +28,24 @@
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 8.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct active once emulation, for TLS. Now all data
+ received by the connection process will be delivered
+ through active once, even when the active once arrives
+ after that the gen_tcp socket is closed by the peer.</p>
+ <p>
+ Own Id: OTP-14300</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 8.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index bfdd0c205b..2eda9d9491 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,6 +1,7 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {<<"8.1.1">>, [{load_module, tls_connection, soft_purge, soft_purge, []}]},
{<<"8\\..*">>, [{restart_application, ssl}]},
{<<"7\\..*">>, [{restart_application, ssl}]},
{<<"6\\..*">>, [{restart_application, ssl}]},
@@ -9,6 +10,7 @@
{<<"3\\..*">>, [{restart_application, ssl}]}
],
[
+ {<<"8.1.1">>, [{load_module, tls_connection, soft_purge, soft_purge, []}]},
{<<"8\\..*">>, [{restart_application, ssl}]},
{<<"7\\..*">>, [{restart_application, ssl}]},
{<<"6\\..*">>, [{restart_application, ssl}]},
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index e06b2fcbd5..831bbefc59 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -397,23 +397,36 @@ handle_info({Protocol, _, Data}, StateName,
end;
handle_info({CloseTag, Socket}, StateName,
#state{socket = Socket, close_tag = CloseTag,
+ socket_options = #socket_options{active = Active},
+ protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs},
negotiated_version = Version} = State) ->
+
%% Note that as of TLS 1.1,
%% failure to properly close a connection no longer requires that a
%% session not be resumed. This is a change from TLS 1.0 to conform
%% with widespread implementation practice.
- case Version of
- {1, N} when N >= 1 ->
- ok;
- _ ->
- %% As invalidate_sessions here causes performance issues,
- %% we will conform to the widespread implementation
- %% practice and go aginst the spec
- %%invalidate_session(Role, Host, Port, Session)
- ok
- end,
- ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
- {stop, {shutdown, transport_closed}};
+
+ case (Active == false) andalso (CTs =/= []) of
+ false ->
+ case Version of
+ {1, N} when N >= 1 ->
+ ok;
+ _ ->
+ %% As invalidate_sessions here causes performance issues,
+ %% we will conform to the widespread implementation
+ %% practice and go aginst the spec
+ %%invalidate_session(Role, Host, Port, Session)
+ ok
+ end,
+
+ ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
+ {stop, {shutdown, transport_closed}};
+ true ->
+ %% Fixes non-delivery of final TLS record in {active, once}.
+ %% Basically allows the application the opportunity to set {active, once} again
+ %% and then receive the final message.
+ next_event(StateName, no_record, State)
+ end;
handle_info(Msg, StateName, State) ->
ssl_connection:handle_info(Msg, StateName, State).
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 415a47949d..82184f5c74 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 8.1.1
+SSL_VSN = 8.1.2