aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/src/ct_hooks.erl11
-rw-r--r--lib/common_test/test/ct_hooks_SUITE.erl10
-rw-r--r--lib/kernel/doc/src/gen_udp.xml87
-rw-r--r--lib/kernel/doc/src/inet.xml50
-rw-r--r--lib/kernel/src/gen_udp.erl75
-rw-r--r--lib/kernel/src/inet.erl16
-rw-r--r--lib/kernel/src/inet6_udp.erl23
-rw-r--r--lib/kernel/src/inet_udp.erl23
-rw-r--r--lib/kernel/src/local_udp.erl8
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl49
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl155
-rw-r--r--lib/public_key/asn1/CMSAesRsaesOaep.asn139
-rw-r--r--lib/public_key/asn1/Makefile2
-rw-r--r--lib/public_key/asn1/OTP-PUB-KEY.set.asn2
-rw-r--r--lib/public_key/doc/src/public_key_app.xml3
-rw-r--r--lib/public_key/src/pubkey_pbe.erl115
-rw-r--r--lib/public_key/test/pbe_SUITE.erl5
-rw-r--r--lib/public_key/test/pbe_SUITE_data/pbes2_aes_128_enc_key.pem30
-rw-r--r--lib/public_key/test/pbe_SUITE_data/pbes2_aes_192_enc_key.pem30
-rw-r--r--lib/public_key/test/pbe_SUITE_data/pbes2_aes_256_enc_key.pem30
-rw-r--r--lib/ssl/src/ssl_handshake.erl2
-rw-r--r--lib/ssl/src/tls_connection.erl3
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl41
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl4
-rw-r--r--lib/stdlib/test/io_SUITE.erl8
25 files changed, 699 insertions, 122 deletions
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index 97c349578f..94551d6815 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -363,7 +363,16 @@ terminate_if_scope_ends(HookId, Function0, Hooks) ->
Function = strip_config(Function0),
case lists:keyfind(HookId, #ct_hook_config.id, Hooks) of
#ct_hook_config{ id = HookId, scope = Function} = Hook ->
- terminate([Hook]),
+ case Function of
+ [AllOrGroup,_] when AllOrGroup=:=post_all;
+ AllOrGroup=:=post_groups ->
+ %% The scope only contains one function (post_all
+ %% or post_groups), and init has not been called,
+ %% so skip terminate as well.
+ ok;
+ _ ->
+ terminate([Hook])
+ end,
lists:keydelete(HookId, #ct_hook_config.id, Hooks);
_ ->
Hooks
diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl
index 03cc7d1e8f..b87464f5e4 100644
--- a/lib/common_test/test/ct_hooks_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE.erl
@@ -675,9 +675,15 @@ test_events(scope_suite_cth) ->
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
%% check that post_groups and post_all comes before init when hook
%% is installed in suite/0
+ %% And there should be no terminate after these, since init is
+ %% not yet called.
{?eh,cth,{'_',post_groups,['_',[]]}},
- {?eh,cth,{'_',post_all,['_','_',[]]}},
- {?eh,tc_start,{ct_scope_suite_cth_SUITE,init_per_suite}},
+ {negative,
+ {?eh,cth,{'_',terminate,['_']}},
+ {?eh,cth,{'_',post_all,['_','_',[]]}}},
+ {negative,
+ {?eh,cth,{'_',terminate,['_']}},
+ {?eh,tc_start,{ct_scope_suite_cth_SUITE,init_per_suite}}},
{?eh,cth,{'_',id,[[]]}},
{?eh,cth,{'_',init,['_',[]]}},
{?eh,cth,{'_',pre_init_per_suite,[ct_scope_suite_cth_SUITE,'$proplist',[]]}},
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index d20fc1fdfd..6c0d072fed 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -213,12 +213,93 @@
</func>
<func>
- <name name="send" arity="4" since=""/>
+ <name name="send" arity="3" since="OTP @OTP-15747@"/>
<fsummary>Send a packet.</fsummary>
<desc>
<p>
- Sends a packet to the specified address and port. Argument
- <c><anno>Address</anno></c> can be a hostname or a socket address.
+ Sends a packet to the specified <c><anno>Destination</anno></c>.
+ </p>
+ <p>
+ This function is equivalent to
+ <seealso marker="#send-4-AncData"><c>send(<anno>Socket</anno>, <anno>Destination</anno>, [], <anno>Packet</anno>)</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="4" clause_i="1" since=""/>
+ <fsummary>Send a packet.</fsummary>
+ <desc>
+ <p>
+ Sends a packet to the specified <c><anno>Host</anno></c>
+ and <c><anno>Port</anno></c>.
+ </p>
+ <p>
+ This clause is equivalent to
+ <seealso marker="#send/5"><c>send(<anno>Socket</anno>, <anno>Host</anno>, <anno>Port</anno>, [], <anno>Packet</anno>)</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="4" clause_i="2" anchor="send-4-AncData" since="OTP @OTP-15747@"/>
+ <fsummary>Send a packet.</fsummary>
+ <desc>
+ <p>
+ Sends a packet to the specified <c><anno>Destination</anno></c>
+ with ancillary data <c><anno>AncData</anno></c>.
+ </p>
+ <note>
+ <p>
+ The ancillary data <c><anno>AncData</anno></c>
+ contains options that for this single message
+ override the default options for the socket,
+ an operation that may not be supported on all platforms,
+ and if so return <c>{error, einval}</c>.
+ Using more than one of an ancillary data item type
+ may also not be supported.
+ <c><anno>AncData</anno> =:= []</c> is always supported.
+ </p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="4" clause_i="3" since="OTP @OTP-15747@"/>
+ <fsummary>Send a packet.</fsummary>
+ <desc>
+ <p>
+ Sends a packet to the specified <c><anno>Destination</anno></c>.
+ Since <c><anno>Destination</anno></c> is complete,
+ <c><anno>PortZero</anno></c> is redundant and has to be <c>0</c>.
+ </p>
+ <p>
+ This is a legacy clause mostly for
+ <c><anno>Destination</anno> = {local, Binary}</c>
+ where <c><anno>PortZero</anno></c> is superfluous.
+ It is equivalent to
+ <seealso marker="#send-4-AncData"><c>send(<anno>Socket</anno>, <anno>Destination</anno>, [], <anno>Packet</anno>)</c></seealso>, the clause right above here.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="5" since="OTP @OTP-15747@"/>
+ <fsummary>Send a packet.</fsummary>
+ <desc>
+ <p>
+ Sends a packet to the specified <c><anno>Host</anno></c>
+ and <c><anno>Port</anno></c>,
+ with ancillary data <c><anno>AncData</anno></c>.
+ </p>
+ <p>
+ Argument <c><anno>Host</anno></c> can be
+ a hostname or a socket address,
+ and <c><anno>Port</anno></c> can be a port number
+ or a service name atom.
+ These are resolved into a <c>Destination</c> and after that
+ this function is equivalent to
+ <seealso marker="#send-4-AncData"><c>send(<anno>Socket</anno>, Destination, <anno>AncData</anno>, <anno>Packet</anno>)</c></seealso>, read there about ancillary data.
</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 5e33bbc3ff..adaa2684d8 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -118,6 +118,42 @@ fe80::204:acff:fe17:bf38
<name name="port_number"/>
</datatype>
<datatype>
+ <name name="family_address" since="OTP @OTP-15747@"/>
+ <desc>
+ <p>
+ A general address format on the form <c>{Family, Destination}</c>
+ where <c>Family</c> is an atom such as <c>local</c>
+ and the format of <c>Destination</c> depends on <c>Family</c>,
+ and is a complete address
+ (for example an IP address including port number).
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="inet_address" since="OTP @OTP-15747@"/>
+ <desc>
+ <warning>
+ <p>
+ This address format is for now experimental
+ and for completeness to make all address families have a
+ <c>{Family, Destination}</c> representation.
+ </p>
+ </warning>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="inet6_address" since="OTP @OTP-15747@"/>
+ <desc>
+ <warning>
+ <p>
+ This address format is for now experimental
+ and for completeness to make all address families have a
+ <c>{Family, Destination}</c> representation.
+ </p>
+ </warning>
+ </desc>
+ </datatype>
+ <datatype>
<name name="local_address"/>
<desc>
<p>
@@ -180,12 +216,16 @@ fe80::204:acff:fe17:bf38
<name name="ancillary_data"/>
<desc>
<p>
- Ancillary data received with the data packet
- or read with the socket option
+ Ancillary data received with the data packet,
+ read with the socket option
<seealso marker="gen_tcp#type-pktoptions_value">
<c>pktoptions</c>
</seealso>
- from a TCP socket.
+ from a TCP socket,
+ or to set in a call to
+ <seealso marker="gen_udp#send-4-AncData"><c>gen_udp:send/4</c></seealso>
+ or
+ <seealso marker="gen_udp#send/5"><c>gen_udp:send/5</c></seealso>.
</p>
<p>
The value(s) correspond to the currently active socket
@@ -193,7 +233,9 @@ fe80::204:acff:fe17:bf38
<seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
<seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
and
- <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>.
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>,
+ or for a single send operation the option(s) to override
+ the currently active socket option(s).
</p>
</desc>
</datatype>
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index d6e8652e77..247ebc50f3 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -20,7 +20,7 @@
-module(gen_udp).
-export([open/1, open/2, close/1]).
--export([send/2, send/4, recv/2, recv/3, connect/3]).
+-export([send/2, send/3, send/4, send/5, recv/2, recv/3, connect/3]).
-export([controlling_process/2]).
-export([fdopen/2]).
@@ -125,20 +125,80 @@ open(Port, Opts0) ->
close(S) ->
inet:udp_close(S).
--spec send(Socket, Address, Port, Packet) -> ok | {error, Reason} when
+-spec send(Socket, Destination, Packet) -> ok | {error, Reason} when
Socket :: socket(),
- Address :: inet:socket_address() | inet:hostname(),
- Port :: inet:port_number(),
+ Destination :: {inet:ip_address(), inet:port_number()} |
+ inet:family_address(),
+ Packet :: iodata(),
+ Reason :: not_owner | inet:posix().
+%%%
+send(Socket, Destination, Packet) ->
+ send(Socket, Destination, [], Packet).
+
+-spec send(Socket, Host, Port, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Host :: inet:hostname() | inet:ip_address(),
+ Port :: inet:port_number() | atom(),
+ Packet :: iodata(),
+ Reason :: not_owner | inet:posix();
+%%%
+ (Socket, Destination, AncData, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Destination :: {inet:ip_address(), inet:port_number()} |
+ inet:family_address(),
+ AncData :: inet:ancillary_data(),
+ Packet :: iodata(),
+ Reason :: not_owner | inet:posix();
+%%%
+ (Socket, Destination, PortZero, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Destination :: {inet:ip_address(), inet:port_number()} |
+ inet:family_address(),
+ PortZero :: inet:port_number(),
Packet :: iodata(),
Reason :: not_owner | inet:posix().
+%%%
+send(S, {_,_} = Destination, PortZero = AncData, Packet) when is_port(S) ->
+ %% Destination is {Family,Addr} | {IP,Port},
+ %% so it is complete - argument PortZero is redundant
+ if
+ PortZero =:= 0 ->
+ case inet_db:lookup_socket(S) of
+ {ok, Mod} ->
+ Mod:send(S, Destination, [], Packet);
+ Error ->
+ Error
+ end;
+ is_integer(PortZero) ->
+ %% Redundant PortZero; must be 0
+ {error, einval};
+ is_list(AncData) ->
+ case inet_db:lookup_socket(S) of
+ {ok, Mod} ->
+ Mod:send(S, Destination, AncData, Packet);
+ Error ->
+ Error
+ end
+ end;
+send(S, Host, Port, Packet) when is_port(S) ->
+ send(S, Host, Port, [], Packet).
-send(S, Address, Port, Packet) when is_port(S) ->
+-spec send(Socket, Host, Port, AncData, Packet) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Host :: inet:hostname() | inet:ip_address() | inet:local_address(),
+ Port :: inet:port_number() | atom(),
+ AncData :: inet:ancillary_data(),
+ Packet :: iodata(),
+ Reason :: not_owner | inet:posix().
+%%%
+send(S, Host, Port, AncData, Packet)
+ when is_port(S), is_list(AncData) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
- case Mod:getaddr(Address) of
+ case Mod:getaddr(Host) of
{ok,IP} ->
case Mod:getserv(Port) of
- {ok,UP} -> Mod:send(S, IP, UP, Packet);
+ {ok,P} -> Mod:send(S, {IP,P}, AncData, Packet);
{error,einval} -> exit(badarg);
Error -> Error
end;
@@ -149,6 +209,7 @@ send(S, Address, Port, Packet) when is_port(S) ->
Error
end.
+%% Connected send
send(S, Packet) when is_port(S) ->
case inet_db:lookup_socket(S) of
{ok, Mod} ->
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 9f22eb6aaa..7940903658 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -75,7 +75,8 @@
-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0,
ip6_address/0, ip_address/0, port_number/0,
- local_address/0, socket_address/0, returned_non_ip_address/0,
+ family_address/0, local_address/0,
+ socket_address/0, returned_non_ip_address/0,
socket_setopt/0, socket_getopt/0, ancillary_data/0,
posix/0, socket/0, stat_option/0]).
%% imports
@@ -100,11 +101,16 @@
0..65535,0..65535,0..65535,0..65535}.
-type ip_address() :: ip4_address() | ip6_address().
-type port_number() :: 0..65535.
--type local_address() :: {local, File :: binary() | string()}.
+-type family_address() :: inet_address() | inet6_address() | local_address().
+-type inet_address() ::
+ {'inet', {ip4_address() | 'any' | 'loopback', port_number()}}.
+-type inet6_address() ::
+ {'inet6', {ip6_address() | 'any' | 'loopback', port_number()}}.
+-type local_address() :: {'local', File :: binary() | string()}.
-type returned_non_ip_address() ::
- {local, binary()} |
- {unspec, <<>>} |
- {undefined, any()}.
+ {'local', binary()} |
+ {'unspec', <<>>} |
+ {'undefined', any()}.
-type posix() ::
'eaddrinuse' | 'eaddrnotavail' | 'eafnosupport' | 'ealready' |
'econnaborted' | 'econnrefused' | 'econnreset' |
diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl
index 71db0357cd..cb95a69798 100644
--- a/lib/kernel/src/inet6_udp.erl
+++ b/lib/kernel/src/inet6_udp.erl
@@ -65,16 +65,25 @@ open(Port, Opts) ->
{ok, _} -> exit(badarg)
end.
-send(S, Addr = {A,B,C,D,E,F,G,H}, P, Data)
- when ?ip6(A,B,C,D,E,F,G,H), ?port(P) ->
- prim_inet:sendto(S, Addr, P, Data).
+send(S, {A,B,C,D,E,F,G,H} = IP, Port, Data)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
+ prim_inet:sendto(S, {IP, Port}, [], Data);
+send(S, {{A,B,C,D,E,F,G,H}, Port} = Addr, AncData, Data)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Addr, AncData, Data);
+send(S, {?FAMILY, {{A,B,C,D,E,F,G,H}, Port}} = Address, AncData, Data)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Address, AncData, Data);
+send(S, {?FAMILY, {loopback, Port}} = Address, AncData, Data)
+ when ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Address, AncData, Data).
send(S, Data) ->
- prim_inet:sendto(S, {0,0,0,0,0,0,0,0}, 0, Data).
+ prim_inet:sendto(S, {any, 0}, [], Data).
-connect(S, Addr = {A,B,C,D,E,F,G,H}, P)
- when ?ip6(A,B,C,D,E,F,G,H), ?port(P) ->
- prim_inet:connect(S, Addr, P).
+connect(S, Addr = {A,B,C,D,E,F,G,H}, Port)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
+ prim_inet:connect(S, Addr, Port).
recv(S, Len) ->
prim_inet:recvfrom(S, Len).
diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl
index 1e624b9e90..083059a2dc 100644
--- a/lib/kernel/src/inet_udp.erl
+++ b/lib/kernel/src/inet_udp.erl
@@ -66,16 +66,25 @@ open(Port, Opts) ->
{ok, _} -> exit(badarg)
end.
-send(S, {A,B,C,D} = Addr, P, Data)
- when ?ip(A,B,C,D), ?port(P) ->
- prim_inet:sendto(S, Addr, P, Data).
+send(S, {A,B,C,D} = IP, Port, Data)
+ when ?ip(A,B,C,D), ?port(Port) ->
+ prim_inet:sendto(S, {IP, Port}, [], Data);
+send(S, {{A,B,C,D}, Port} = Addr, AncData, Data)
+ when ?ip(A,B,C,D), ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Addr, AncData, Data);
+send(S, {?FAMILY, {{A,B,C,D}, Port}} = Address, AncData, Data)
+ when ?ip(A,B,C,D), ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Address, AncData, Data);
+send(S, {?FAMILY, {loopback, Port}} = Address, AncData, Data)
+ when ?port(Port), is_list(AncData) ->
+ prim_inet:sendto(S, Address, AncData, Data).
send(S, Data) ->
- prim_inet:sendto(S, {0,0,0,0}, 0, Data).
+ prim_inet:sendto(S, {any, 0}, [], Data).
-connect(S, Addr = {A,B,C,D}, P)
- when ?ip(A,B,C,D), ?port(P) ->
- prim_inet:connect(S, Addr, P).
+connect(S, Addr = {A,B,C,D}, Port)
+ when ?ip(A,B,C,D), ?port(Port) ->
+ prim_inet:connect(S, Addr, Port).
recv(S, Len) ->
prim_inet:recvfrom(S, Len).
diff --git a/lib/kernel/src/local_udp.erl b/lib/kernel/src/local_udp.erl
index 481a8c4910..933e56228b 100644
--- a/lib/kernel/src/local_udp.erl
+++ b/lib/kernel/src/local_udp.erl
@@ -70,11 +70,13 @@ open(0, Opts) ->
{ok, _} -> exit(badarg)
end.
-send(S, Addr = {?FAMILY,_}, 0, Data) ->
- prim_inet:sendto(S, Addr, 0, Data).
+send(S, {?FAMILY,_} = Addr, 0, Data) ->
+ prim_inet:sendto(S, Addr, [], Data);
+send(S, {?FAMILY,_} = Addr, AncData, Data) when is_list(AncData) ->
+ prim_inet:sendto(S, Addr, AncData, Data).
%%
send(S, Data) ->
- prim_inet:sendto(S, {?FAMILY,<<>>}, 0, Data).
+ prim_inet:sendto(S, {?FAMILY,<<>>}, [], Data).
connect(S, Addr = {?FAMILY,_}, 0) ->
prim_inet:connect(S, Addr, 0).
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 52edfaee29..1ff30012e1 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -36,7 +36,8 @@
show_econnreset_passive/1, econnreset_after_sync_send/1,
econnreset_after_async_send_active/1,
econnreset_after_async_send_active_once/1,
- econnreset_after_async_send_passive/1, linger_zero/1,
+ econnreset_after_async_send_passive/1,
+ linger_zero/1, linger_zero_sndbuf/1,
default_options/1, http_bad_packet/1,
busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1,
fill_sendq/1, partial_recv_and_close/1,
@@ -80,7 +81,8 @@ all() ->
show_econnreset_passive, econnreset_after_sync_send,
econnreset_after_async_send_active,
econnreset_after_async_send_active_once,
- econnreset_after_async_send_passive, linger_zero,
+ econnreset_after_async_send_passive,
+ linger_zero, linger_zero_sndbuf,
default_options, http_bad_packet, busy_send,
busy_disconnect_passive, busy_disconnect_active,
fill_sendq, partial_recv_and_close,
@@ -1356,7 +1358,42 @@ linger_zero(Config) when is_list(Config) ->
ok = gen_tcp:close(Client),
ok = ct:sleep(1),
undefined = erlang:port_info(Client, connected),
- {error, econnreset} = gen_tcp:recv(S, PayloadSize).
+ {error, econnreset} = gen_tcp:recv(S, PayloadSize),
+ ok.
+
+
+linger_zero_sndbuf(Config) when is_list(Config) ->
+ %% All the econnreset tests will prove that {linger, {true, 0}} aborts
+ %% a connection when the driver queue is empty. We will test here
+ %% that it also works when the driver queue is not empty
+ %% and the linger zero option is set on the listen socket.
+ {OS, _} = os:type(),
+ {ok, Listen} =
+ gen_tcp:listen(0, [{active, false},
+ {recbuf, 4096},
+ {show_econnreset, true},
+ {linger, {true, 0}}]),
+ {ok, Port} = inet:port(Listen),
+ {ok, Client} =
+ gen_tcp:connect(localhost, Port,
+ [{active, false},
+ {sndbuf, 4096}]),
+ {ok, Server} = gen_tcp:accept(Listen),
+ ok = gen_tcp:close(Listen),
+ PayloadSize = 1024 * 1024,
+ Payload = binary:copy(<<"0123456789ABCDEF">>, 256 * 1024), % 1 MB
+ ok = gen_tcp:send(Server, Payload),
+ case erlang:port_info(Server, queue_size) of
+ {queue_size, N} when N > 0 -> ok;
+ {queue_size, 0} when OS =:= win32 -> ok;
+ {queue_size, 0} = T -> ct:fail(T)
+ end,
+ {ok, [{linger, {true, 0}}]} = inet:getopts(Server, [linger]),
+ ok = gen_tcp:close(Server),
+ ok = ct:sleep(1),
+ undefined = erlang:port_info(Server, connected),
+ {error, closed} = gen_tcp:recv(Client, PayloadSize),
+ ok.
%% Thanks to Luke Gorrie. Tests for a very specific problem with
@@ -1984,7 +2021,7 @@ recvtclass(_Config) ->
recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
%% Using the option returns einval, so it is not implemented.
-recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
%% Does not return any value - not implemented for pktoptions
recvtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
@@ -1996,7 +2033,7 @@ recvtos_ok(_, _) -> false.
recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
%% Using the option returns einval, so it is not implemented.
-recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
%% Does not return any value - not implemented for pktoptions
recvttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,7,0});
@@ -2009,7 +2046,7 @@ recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
%% Using the option returns einval, so it is not implemented.
-recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
%% Does not return any value - not implemented for pktoptions
recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
%%
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index af9985de45..730886865c 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -37,6 +37,7 @@
buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1,
read_packets/1, open_fd/1, connect/1, implicit_inet6/1,
recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1,
+ sendtos/1, sendtosttl/1, sendttl/1, sendtclass/1,
local_basic/1, local_unbound/1,
local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]).
@@ -49,6 +50,7 @@ all() ->
bad_address, read_packets, open_fd, connect,
implicit_inet6, active_n,
recvtos, recvtosttl, recvttl, recvtclass,
+ sendtos, sendtosttl, sendttl, sendtclass,
{group, local}].
groups() ->
@@ -312,7 +314,6 @@ read_packets(Config) when is_list(Config) ->
{ok,R} = gen_udp:open(0, [{read_packets,N1}]),
{ok,RP} = inet:port(R),
{ok,Node} = start_node(gen_udp_SUITE_read_packets),
- Die = make_ref(),
%%
{V1, Trace1} = read_packets_test(R, RP, Msgs, Node),
{ok,[{read_packets,N1}]} = inet:getopts(R, [read_packets]),
@@ -324,7 +325,7 @@ read_packets(Config) when is_list(Config) ->
stop_node(Node),
ct:log("N1=~p, V1=~p vs N2=~p, V2=~p",[N1,V1,N2,V2]),
- dump_terms(Config, "trace1.terms", Trace2),
+ dump_terms(Config, "trace1.terms", Trace1),
dump_terms(Config, "trace2.terms", Trace2),
%% Because of the inherit racy-ness of the feature it is
@@ -348,15 +349,6 @@ dump_terms(Config, Name, Terms) ->
file:write_file(FName, term_to_binary(Terms)),
ct:log("Logged terms to ~s",[FName]).
-infinite_loop(Die) ->
- receive
- Die ->
- ok
- after
- 0 ->
- infinite_loop(Die)
- end.
-
read_packets_test(R, RP, Msgs, Node) ->
Receiver = self(),
Tracer =
@@ -577,19 +569,19 @@ active_n(Config) when is_list(Config) ->
recvtos(_Config) ->
test_recv_opts(
- inet, [{recvtos,tos,96}],
+ inet, [{recvtos,tos,96}], false,
fun recvtos_ok/2).
recvtosttl(_Config) ->
test_recv_opts(
- inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}], false,
fun (OSType, OSVer) ->
recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
end).
recvttl(_Config) ->
test_recv_opts(
- inet, [{recvttl,ttl,33}],
+ inet, [{recvttl,ttl,33}], false,
fun recvttl_ok/2).
recvtclass(_Config) ->
@@ -601,15 +593,48 @@ recvtclass(_Config) ->
of
[_] ->
test_recv_opts(
- inet6, [{recvtclass,tclass,224}],
+ inet6, [{recvtclass,tclass,224}], false,
fun recvtclass_ok/2);
[] ->
{skip,ipv6_not_supported,IFs}
end.
+
+sendtos(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96}], true,
+ fun sendtos_ok/2).
+
+sendtosttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}], true,
+ fun (OSType, OSVer) ->
+ sendtos_ok(OSType, OSVer) andalso sendttl_ok(OSType, OSVer)
+ end).
+
+sendttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvttl,ttl,33}], true,
+ fun sendttl_ok/2).
+
+sendtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_recv_opts(
+ inet6, [{recvtclass,tclass,224}], true,
+ fun sendtclass_ok/2);
+ [] ->
+ {skip,ipv6_not_supported,IFs}
+ end.
+
%% These version numbers are just above the highest noted in daily tests
%% where the test fails for a plausible reason, that is the lowest
-%% where we can expect that the test mighe succeed, so
+%% where we can expect that the test might succeed, so
%% skip on platforms lower than this.
%%
%% On newer versions it might be fixed, but we'll see about that
@@ -628,16 +653,55 @@ recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
recvtos_ok({unix,_}, _) -> true;
recvtos_ok(_, _) -> false.
+%% Option has no effect
+recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%%
recvttl_ok({unix,_}, _) -> true;
recvttl_ok(_, _) -> false.
%% Using the option returns einval, so it is not implemented.
recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0});
recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11});
+%% Option has no effect
+recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
%%
recvtclass_ok({unix,_}, _) -> true;
recvtclass_ok(_, _) -> false.
+
+%% To send ancillary data seems to require much higher version numbers
+%% than receiving it...
+%%
+
+%% Using the option returns einval, so it is not implemented.
+sendtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
+sendtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,5,0});
+sendtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+sendtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {4,0,0});
+sendtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
+%%
+sendtos_ok({unix,_}, _) -> true;
+sendtos_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+sendttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
+sendttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {4,0,0});
+%% Using the option returns enoprotoopt, so it is not implemented.
+sendttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0});
+%% Option has no effect
+sendttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,5,0});
+%%
+sendttl_ok({unix,_}, _) -> true;
+sendttl_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+sendtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0});
+sendtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11});
+%%
+sendtclass_ok({unix,_}, _) -> true;
+sendtclass_ok(_, _) -> false.
+
+
semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
if
X1 > X2 -> false;
@@ -650,18 +714,18 @@ semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
end;
semver_lt(_, {_,_,_}) -> false.
-test_recv_opts(Family, Spec, OSFilter) ->
+test_recv_opts(Family, Spec, TestSend, OSFilter) ->
OSType = os:type(),
OSVer = os:version(),
case OSFilter(OSType, OSVer) of
true ->
io:format("Os: ~p, ~p~n", [OSType,OSVer]),
- test_recv_opts(Family, Spec, OSType, OSVer);
+ test_recv_opts(Family, Spec, TestSend, OSType, OSVer);
false ->
{skip,{not_supported_for_os_version,{OSType,OSVer}}}
end.
%%
-test_recv_opts(Family, Spec, _OSType, _OSVer) ->
+test_recv_opts(Family, Spec, TestSend, _OSType, _OSVer) ->
Timeout = 5000,
RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
@@ -686,16 +750,33 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) ->
ok = inet:setopts(S1, TrueRecvOpts_OptsVals),
{ok,TrueRecvOpts_OptsVals} = inet:getopts(S1, RecvOpts ++ Opts),
%%
+ %% S1 now has true receive options and set option values
+ %%
{ok,S2} =
gen_udp:open(0, [Family,binary,{active,true}|FalseRecvOpts]),
{ok,P2} = inet:port(S2),
{ok,FalseRecvOpts_OptsVals2} = inet:getopts(S2, RecvOpts ++ Opts),
OptsVals2 = FalseRecvOpts_OptsVals2 -- FalseRecvOpts,
%%
- ok = gen_udp:send(S2, Addr, P1, <<"abcde">>),
+ %% S2 now has false receive options and default option values,
+ %% OptsVals2 contains the default option values
+ %%
+ ok = gen_udp:send(S2, {Addr,P1}, <<"abcde">>),
ok = gen_udp:send(S1, Addr, P2, <<"fghij">>),
+ TestSend andalso
+ begin
+ ok = gen_udp:send(S2, Addr, P1, OptsVals, <<"ABCDE">>),
+ ok = gen_udp:send(S2, {Addr,P1}, OptsVals, <<"12345">>)
+ end,
{ok,{_,P2,OptsVals3,<<"abcde">>}} = gen_udp:recv(S1, 0, Timeout),
verify_sets_eq(OptsVals3, OptsVals2),
+ TestSend andalso
+ begin
+ {ok,{_,P2,OptsVals0,<<"ABCDE">>}} = gen_udp:recv(S1, 0, Timeout),
+ {ok,{_,P2,OptsVals1,<<"12345">>}} = gen_udp:recv(S1, 0, Timeout),
+ verify_sets_eq(OptsVals0, OptsVals),
+ verify_sets_eq(OptsVals1, OptsVals)
+ end,
receive
{udp,S2,_,P1,<<"fghij">>} ->
ok;
@@ -710,8 +791,16 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) ->
ok = inet:setopts(S2, TrueRecvOpts),
{ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
%%
- ok = gen_udp:send(S2, Addr, P1, <<"klmno">>),
- ok = gen_udp:send(S1, Addr, P2, <<"pqrst">>),
+ %% S1 now has false receive options and set option values
+ %%
+ %% S2 now has true receive options and default option values
+ %%
+ ok = gen_udp:send(S2, {Addr,P1}, [], <<"klmno">>),
+ ok = gen_udp:send(S1, {Family,{loopback,P2}}, <<"pqrst">>),
+ TestSend andalso
+ begin
+ ok = gen_udp:send(S1, {Family,{loopback,P2}}, OptsVals2, <<"PQRST">>)
+ end,
{ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout),
receive
{udp,S2,_,P1,OptsVals4,<<"pqrst">>} ->
@@ -721,9 +810,18 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) ->
after Timeout ->
exit(timeout)
end,
+ TestSend andalso
+ receive
+ {udp,S2,_,P1,OptsVals5,<<"PQRST">>} ->
+ verify_sets_eq(OptsVals5, OptsVals2);
+ Other3 ->
+ exit({unexpected,Other3})
+ after Timeout ->
+ exit(timeout)
+ end,
ok = gen_udp:close(S1),
ok = gen_udp:close(S2),
-%% exit({{OSType,OSVer},success}), % In search for the truth
+%%% exit({{_OSType,_OSVer},success}), % In search for the truth
ok.
verify_sets_eq(L1, L2) ->
@@ -877,6 +975,10 @@ connect(Config) when is_list(Config) ->
implicit_inet6(Config) when is_list(Config) ->
Host = ok(inet:gethostname()),
case inet:getaddr(Host, inet6) of
+ {ok,{16#fe80,0,0,0,_,_,_,_} = Addr} ->
+ {skip,
+ "Got link local IPv6 address: "
+ ++inet:ntoa(Addr)};
{ok,Addr} ->
implicit_inet6(Host, Addr);
{error,Reason} ->
@@ -927,11 +1029,12 @@ ok({ok,V}) -> V;
ok(NotOk) ->
try throw(not_ok)
catch
- throw:Thrown:Stacktrace ->
- erlang:raise(
- error, {Thrown, NotOk}, tl(Stacktrace))
+ throw:not_ok:Stacktrace ->
+ raise_error({not_ok, NotOk}, tl(Stacktrace))
end.
+raise_error(Reason, Stacktrace) ->
+ erlang:raise(error, Reason, Stacktrace).
local_filename(Tag) ->
"/tmp/" ?MODULE_STRING "_" ++ os:getpid() ++ "_" ++ atom_to_list(Tag).
diff --git a/lib/public_key/asn1/CMSAesRsaesOaep.asn1 b/lib/public_key/asn1/CMSAesRsaesOaep.asn1
new file mode 100644
index 0000000000..ca8c7b7f92
--- /dev/null
+++ b/lib/public_key/asn1/CMSAesRsaesOaep.asn1
@@ -0,0 +1,39 @@
+CMSAesRsaesOaep {iso(1) member-body(2) us(840) rsadsi(113549)
+ pkcs(1) pkcs-9(9) smime(16) modules(0) id-mod-cms-aes(19) }
+
+
+DEFINITIONS IMPLICIT TAGS ::=
+BEGIN
+
+-- EXPORTS ALL --
+IMPORTS
+ -- PKIX
+ AlgorithmIdentifier
+ FROM PKIX1Explicit88 {iso(1) identified-organization(3) dod(6)
+ internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
+ id-pkix1-explicit(18)};
+
+-- AES information object identifiers --
+
+aes OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
+ organization(1) gov(101) csor(3) nistAlgorithms(4) 1 }
+
+-- AES using CBC-chaining mode for key sizes of 128, 192, 256
+
+id-aes128-CBC OBJECT IDENTIFIER ::= { aes 2 }
+id-aes192-CBC OBJECT IDENTIFIER ::= { aes 22 }
+id-aes256-CBC OBJECT IDENTIFIER ::= { aes 42 }
+
+-- AES-IV is a the parameter for all the above object identifiers.
+
+AES-IV ::= OCTET STRING (SIZE(16))
+
+
+-- AES Key Wrap Algorithm Identifiers - Parameter is absent
+
+id-aes128-wrap OBJECT IDENTIFIER ::= { aes 5 }
+id-aes192-wrap OBJECT IDENTIFIER ::= { aes 25 }
+id-aes256-wrap OBJECT IDENTIFIER ::= { aes 45 }
+
+
+END
diff --git a/lib/public_key/asn1/Makefile b/lib/public_key/asn1/Makefile
index a920ea87ea..10952106c6 100644
--- a/lib/public_key/asn1/Makefile
+++ b/lib/public_key/asn1/Makefile
@@ -42,7 +42,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/public_key-$(VSN)
ASN_TOP = OTP-PUB-KEY PKCS-FRAME
ASN_MODULES = PKIX1Explicit88 PKIX1Implicit88 PKIX1Algorithms88 \
PKIXAttributeCertificate PKCS-1 PKCS-3 PKCS-7 PKCS-8 PKCS-10 PKCS5v2-0 OTP-PKIX \
- InformationFramework RFC5639
+ InformationFramework RFC5639 CMSAesRsaesOaep
ASN_ASNS = $(ASN_MODULES:%=%.asn1)
ASN_ERLS = $(ASN_TOP:%=%.erl)
ASN_HRLS = $(ASN_TOP:%=%.hrl)
diff --git a/lib/public_key/asn1/OTP-PUB-KEY.set.asn b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
index b3f3ccdb77..7ab1684ff3 100644
--- a/lib/public_key/asn1/OTP-PUB-KEY.set.asn
+++ b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
@@ -10,3 +10,5 @@ ECPrivateKey.asn1
PKCS-7.asn1
PKCS-10.asn1
RFC5639.asn1
+CMSAesRsaesOaep.asn1
+
diff --git a/lib/public_key/doc/src/public_key_app.xml b/lib/public_key/doc/src/public_key_app.xml
index 923a9f1dfb..5f2c50711a 100644
--- a/lib/public_key/doc/src/public_key_app.xml
+++ b/lib/public_key/doc/src/public_key_app.xml
@@ -51,6 +51,9 @@
Diffie-Hellman Key Agreement Standard </item>
<item>Supports <url href="http://www.ietf.org/rfc/rfc2898.txt"> PKCS-5</url> -
Password-Based Cryptography Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/fc3565.txt"> AES </url> -
+ Use of the Advanced Encryption Standard (AES) Algorithm in Cryptographic Message Syntax (CMS)
+ </item>
<item>Supports <url href="http://www.ietf.org/rfc/rfc5208.txt"> PKCS-8</url> -
Private-Key Information Syntax Standard</item>
<item>Supports <url href="http://www.ietf.org/rfc/rfc5967.txt"> PKCS-10</url> -
diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl
index 806f7c5b0f..b9fe219dcf 100644
--- a/lib/public_key/src/pubkey_pbe.erl
+++ b/lib/public_key/src/pubkey_pbe.erl
@@ -26,9 +26,7 @@
-export([encode/4, decode/4, decrypt_parameters/1, encrypt_parameters/1]).
-export([pbdkdf1/4, pbdkdf2/7]).
--define(DEFAULT_SHA_MAC_KEYLEN, 20).
-define(ASN1_OCTET_STR_TAG, 4).
--define(IV_LEN, 8).
%%====================================================================
%% Internal application API
@@ -41,16 +39,21 @@
%%--------------------------------------------------------------------
encode(Data, Password, "DES-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:block_encrypt(des_cbc, Key, IV, pbe_pad(Data, KeyDevParams));
-
+ crypto:block_encrypt(des_cbc, Key, IV, pbe_pad(Data, block_size(des_cbc)));
encode(Data, Password, "DES-EDE3-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:block_encrypt(des3_cbc, [Key1, Key2, Key3], IV, pbe_pad(Data));
-
+ crypto:block_encrypt(des3_cbc, [Key1, Key2, Key3], IV, pbe_pad(Data, block_size(des_3ede)));
encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:block_encrypt(rc2_cbc, Key, IV, pbe_pad(Data, KeyDevParams)).
+ crypto:block_encrypt(rc2_cbc, Key, IV, pbe_pad(Data, block_size(rc2_cbc)));
+encode(Data, Password, "AES-128-CBC" = Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_encrypt(aes_cbc128, Key, IV, pbe_pad(Data, block_size(aes_128_cbc)));
+encode(Data, Password, "AES-256-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_encrypt(aes_cbc256, Key, IV, pbe_pad(Data, block_size(aes_256_cbc))).
+
%%--------------------------------------------------------------------
-spec decode(binary(), string(), string(), term()) -> binary().
%%
@@ -59,21 +62,19 @@ encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
decode(Data, Password,"DES-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
crypto:block_decrypt(des_cbc, Key, IV, Data);
-
decode(Data, Password,"DES-EDE3-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
crypto:block_decrypt(des3_cbc, [Key1, Key2, Key3], IV, Data);
-
decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
crypto:block_decrypt(rc2_cbc, Key, IV, Data);
-
-decode(Data, Password,"AES-128-CBC"= Cipher, IV) ->
- %% PKCS5_SALT_LEN is 8 bytes
- <<Salt:8/binary,_/binary>> = IV,
- {Key, _} = password_to_key_and_iv(Password, Cipher, Salt),
- crypto:block_decrypt(aes_cbc128, Key, IV, Data).
+decode(Data, Password,"AES-128-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_decrypt(aes_cbc128, Key, IV, Data);
+decode(Data, Password,"AES-256-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_decrypt(aes_cbc256, Key, IV, Data).
%%--------------------------------------------------------------------
-spec pbdkdf1(string(), iodata(), integer(), atom()) -> binary().
@@ -131,13 +132,15 @@ password_to_key_and_iv(Password, _Cipher, {#'PBEParameter'{salt = Salt,
<<Key:8/binary, IV:8/binary, _/binary>>
= pbdkdf1(Password, Salt, Count, Hash),
{Key, IV};
-password_to_key_and_iv(Password, Cipher, Salt) ->
- KeyLen = derived_key_length(Cipher, undefined),
+password_to_key_and_iv(Password, Cipher, KeyDevParams) ->
+ %% PKCS5_SALT_LEN is 8 bytes
+ <<Salt:8/binary,_/binary>> = KeyDevParams,
+ KeyLen = derived_key_length(Cipher, undefined),
<<Key:KeyLen/binary, _/binary>> =
pem_encrypt(<<>>, Password, Salt, ceiling(KeyLen div 16), <<>>, md5),
%% Old PEM encryption does not use standard encryption method
- %% pbdkdf1 and uses then salt as IV
- {Key, Salt}.
+ %% pbdkdf1
+ {Key, KeyDevParams}.
pem_encrypt(_, _, _, 0, Acc, _) ->
Acc;
pem_encrypt(Prev, Password, Salt, Count, Acc, Hash) ->
@@ -150,17 +153,15 @@ do_pbdkdf1(Prev, Count, Acc, Hash) ->
Result = crypto:hash(Hash, Prev),
do_pbdkdf1(Result, Count-1 , <<Result/binary, Acc/binary>>, Hash).
-iv(#'PBES2-params_encryptionScheme'{algorithm = Algo,
- parameters = ASN1IV})
- when (Algo == ?'desCBC') or
- (Algo == ?'des-EDE3-CBC') ->
- <<?ASN1_OCTET_STR_TAG, ?IV_LEN, IV:?IV_LEN/binary>> = decode_handle_open_type_wrapper(ASN1IV),
- IV;
iv(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC',
parameters = ASN1IV}) ->
{ok, #'RC2-CBC-Parameter'{iv = IV}}
= 'PKCS-FRAME':decode('RC2-CBC-Parameter', decode_handle_open_type_wrapper(ASN1IV)),
- iolist_to_binary(IV).
+ iolist_to_binary(IV);
+iv(#'PBES2-params_encryptionScheme'{algorithm = _Algo,
+ parameters = ASN1IV}) ->
+ <<?ASN1_OCTET_STR_TAG, Len:8/unsigned-big-integer, IV:Len/binary>> = decode_handle_open_type_wrapper(ASN1IV),
+ IV.
blocks(1, N, Index, Password, Salt, Count, Prf, PrfHash, PrfLen, Acc) ->
<<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen),
@@ -217,17 +218,9 @@ pbe1_oid("RC2-CBC", md5) ->
pbe1_oid("DES-CBC", md5) ->
?'pbeWithMD5AndDES-CBC'.
-pbe_pad(Data, {#'PBEParameter'{}, _}) ->
- pbe_pad(Data);
-pbe_pad(Data, #'PBES2-params'{}) ->
- pbe_pad(Data);
-pbe_pad(Data, _) ->
-pbe_pad(Data).%% Data.
-
-
-pbe_pad(Data) ->
- N = 8 - (erlang:byte_size(Data) rem 8),
- Pad = list_to_binary(lists:duplicate(N, N)),
+pbe_pad(Data, BlockSize) ->
+ N = BlockSize - (erlang:byte_size(Data) rem BlockSize),
+ Pad = binary:copy(<<N>>, N),
<<Data/binary, Pad/binary>>.
key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc,
@@ -249,11 +242,27 @@ key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc,
pseudo_random_function(#'PBKDF2-params_prf'{algorithm =
{_,_, _,'id-hmacWithSHA1'}}) ->
{fun crypto:hmac/4, sha, pseudo_output_length(?'id-hmacWithSHA1')};
-pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA1'}) ->
- {fun crypto:hmac/4, sha, pseudo_output_length(?'id-hmacWithSHA1')}.
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA1' = Algo}) ->
+ {fun crypto:hmac/4, sha, pseudo_output_length(Algo)};
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA224'= Algo}) ->
+ {fun crypto:hmac/4, sha224, pseudo_output_length(Algo)};
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA256' = Algo}) ->
+ {fun crypto:hmac/4, sha256, pseudo_output_length(Algo)};
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA384' = Algo}) ->
+ {fun crypto:hmac/4, sha384, pseudo_output_length(Algo)};
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA512' = Algo}) ->
+ {fun crypto:hmac/4, sha512, pseudo_output_length(Algo)}.
pseudo_output_length(?'id-hmacWithSHA1') ->
- ?DEFAULT_SHA_MAC_KEYLEN.
+ 20; %%160/8
+pseudo_output_length(?'id-hmacWithSHA224') ->
+ 28; %%%224/8
+pseudo_output_length(?'id-hmacWithSHA256') ->
+ 32; %%256/8
+pseudo_output_length(?'id-hmacWithSHA384') ->
+ 48; %%384/8
+pseudo_output_length(?'id-hmacWithSHA512') ->
+ 64. %%512/8
derived_key_length(_, Len) when is_integer(Len) ->
Len;
@@ -266,9 +275,33 @@ derived_key_length(Cipher,_) when (Cipher == ?'rc2CBC') or
derived_key_length(Cipher,_) when (Cipher == ?'des-EDE3-CBC') or
(Cipher == "DES-EDE3-CBC") ->
24;
-derived_key_length(Cipher,_) when (Cipher == "AES-128-CBC") ->
+
+derived_key_length(Cipher,_) when (Cipher == "AES-128-CBC");
+ (Cipher == ?'id-aes128-CBC') ->
+ 16;
+derived_key_length(Cipher,_) when (Cipher == "AES-192-CBC");
+ (Cipher == ?'id-aes192-CBC') ->
+ 24;
+
+derived_key_length(Cipher,_) when (Cipher == "AES-256-CBC");
+ (Cipher == ?'id-aes256-CBC') ->
+ 32.
+
+block_size(Cipher) when Cipher == rc2_cbc;
+ Cipher == des_cbc;
+ Cipher == des_3ede ->
+ 8;
+block_size(Cipher) when Cipher == aes_128_cbc;
+ Cipher == aes_192_cbc;
+ Cipher == aes_256_cbc ->
16.
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'id-aes128-CBC'}) ->
+ "AES-128-CBC";
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'id-aes192-CBC'}) ->
+ "AES-192-CBC";
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'id-aes256-CBC'}) ->
+ "AES-256-CBC";
cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'desCBC'}) ->
"DES-CBC";
cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'des-EDE3-CBC'}) ->
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 523c9e2515..5dea35dce6 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -218,7 +218,9 @@ pbes2() ->
[{doc,"Tests encode/decode EncryptedPrivateKeyInfo encrypted with different ciphers using PBES2"}].
pbes2(Config) when is_list(Config) ->
decode_encode_key_file("pbes2_des_cbc_enc_key.pem", "password", "DES-CBC", Config),
- decode_encode_key_file("pbes2_des_ede3_cbc_enc_key.pem", "password", "DES-EDE3-CBC", Config),
+ decode_encode_key_file("pbes2_des_ede3_cbc_enc_key.pem", "password", "DES-EDE3-CBC", Config),
+ decode_encode_key_file("pbes2_aes_128_enc_key.pem", "password", "AES-128-CBC", Config),
+ decode_encode_key_file("pbes2_aes_256_enc_key.pem", "password", "AES-256-CBC", Config),
case lists:member(rc2_cbc, proplists:get_value(ciphers, crypto:supports())) of
true ->
decode_encode_key_file("pbes2_rc2_cbc_enc_key.pem", "password", "RC2-CBC", Config);
@@ -231,7 +233,6 @@ decode_encode_key_file(File, Password, Cipher, Config) ->
{ok, PemKey} = file:read_file(filename:join(Datadir, File)),
PemEntry = public_key:pem_decode(PemKey),
- ct:print("Pem entry: ~p" , [PemEntry]),
[{Asn1Type, _, {Cipher,_} = CipherInfo} = PubEntry] = PemEntry,
#'RSAPrivateKey'{} = KeyInfo = public_key:pem_entry_decode(PubEntry, Password),
PemKey1 = public_key:pem_encode([public_key:pem_entry_encode(Asn1Type, KeyInfo, {CipherInfo, Password})]),
diff --git a/lib/public_key/test/pbe_SUITE_data/pbes2_aes_128_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_128_enc_key.pem
new file mode 100644
index 0000000000..5702119ad6
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_128_enc_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIWrPgmqJqNpICAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBA/bbIMYqQMUDxMk9ifPR7ABIIE
+0Drfqke1/ccFxk786hTh36yjVo48Xx7B3Scb92KtmyQpNaR6GbR+jhP9cxIcvmGN
+YroCB896VJSIx8PraqGgIJ1hblZXyfLanB0mUnZvaaQ4xp3UJT53a0yOm5Lfd+fB
+0TyaoEzca2jA5EVVh3yH6gzNsvQJRw6cQP5CAptLjiUv2jrwVGnO8x8X4egJDLZS
+Sb8B5AW8h1sGsyKEEFto6gpBjVqnVn5veMoI/Cfs9qDr071+dhbps/m6pseKKp0z
+8qeFM7+9Y4npD1VYg2gqOFi19QAI3gwq6tC8grOzRA8dPFUgpV9eMToVsI2OFQc1
+xnFZEV7NZVymh5HjKM1jwFy6es+5TFoMtRu6vDxKS6Y13lIlZ4oQSh8aXtG5Ylt2
+CqsKNHyDbZUpvKe/k19TBmVXQBCYFuN733jI9/4JBtpygnxwt1aXCvq/PFFGsTS4
+p1JOQvr/jaD7b4JO6IMXH1kSVxiMXKXNG7wPUNr6OWJvc7OqdclsZa7ibEx4L52x
+DuFmsxQo4a3iibhbcjr436OmR5Uw2UAstB5qxWfMhkt+e7rRhCOh/3O7SAYEpt+f
+Zr2VFXdGme4kR6uMCzgGiSh0qCseQXpJUZVufn/Go9r+601OJTJIQ9a2VoqlMR8o
+Dd14D0gBXXaZkY60Mh8iXR/MjKDuv0KBUyBzfcpk3fLmv0PhGSkbn6j+q1jZbogm
+EhI0AL5s2EoofuBdvgdusBhCrrwCMonprqR7BuaKPD0GEw5utnT5ovcUg/sjMJox
+10100QwAzQScU4iG/xic/TsN+ZMumhUcYs003MsZkRLvCEFxZurEMx7819CqfhIc
+NGd7ETTBSwoNf5pXRTHaTbW6pPiIeWunLUUVsRcNoBtL/cXmg+mu1zdsD7nD51mJ
+vG9A7LPW7XVl2Jv2NgQoKkHYO7cVozmcz6AE2z1q+XN4LGto8JEZktb6E7UIyXXg
+Ls4Tv0sn5TLgtaJ31w4+9iybNiGoVYOc4h0s5DoNR4ivcZ6n/Qnf8PTrNzejEJY6
+R/UnDbc24u0palGc1kei99d0BYodnq4OlAj7M7ML0GncftInhgA0Dp81YG5PujMa
+irhvwtnD5Xysfh1YrroAEN7Qxc8+2JlpgNSFlFFkMgfibc6jvTX6/C6MaFz8hiOq
+W43ZBEzjMIs23ZrJKOJGsuTdHSob+VbvqIMgS2PeGb/6g3/GjdipCbynNhX3zUOM
+3j/lpZOiAwE/Bftr5FOSfTFpnyorIIeyWgROEZTTL4eSYvnBjzf+tUdXY7ltxJie
+q0rpQ42X7+B4gTo8Qj/xC7LXSCldERK57cCwwITvjcHwxPyOiJ9BMI1HlRQ/Fo3C
+lPYIst1xjJ67qrTm6mWkor2hUOZcg4MOOzXWuijWRGJ/Wz0H+GKWtoE2X536D6sy
+a4Nwwj09oFY4Fph/SUNwy0MLpTSzikpUx6mxjbs3Odvo6tWWVcicp/dCWYCqLpGU
+3axEb/qlsaRNtKJg9O3Fq7hh1BTyLNGB2ET5wSKtlSD0bDeF15bBvkHB3z2/lDls
+YQ2hEHMjeSEZZyGTPqEHwtBuUwiWBBXwOIhT8nfYXbHWR0CLBLth2+E/JCaO9hD2
+V277arqNFa8nugZMwS+ragi6vbgIX4BiS/rnfYXgqaxD
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/lib/public_key/test/pbe_SUITE_data/pbes2_aes_192_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_192_enc_key.pem
new file mode 100644
index 0000000000..ee82e9f667
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_192_enc_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIcqBCM7v+ZlkCAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEWBBD93r4IWBhvry+cdfwIDOKeBIIE
+0DXM8S70sMsUmwxRZQtKwGfYddEWIc9lrEdsgEEuonF6NrseRq7QdXnBSPwq5f0O
+ofMZ/0OCun3Qg1ls1EdsyKdijSOq27ZhHCnmWi1Rw1ApJIAq5i/jY8U17+lUakvG
+VtcsuRzlKmFxbBW44kLK7vK6xiA76HPx0I4ZXcdywR0pbLT1ubbhbQ9djLnBiYkT
+odszGTyxNceEse1Hu/RhFK17tnwov0fdioKY2i9F7qfq8lYLPrusEKTY7tOVjFOh
+bXeCry1BL0KTt65JVGR9xQCI0qokEU0QrCgD6skq7Vx2C/Ho1sW6h8FBFVIm6ozO
+bEUtVk3Xgs5yieetha1GxJAang1VxAPemnXfOmVapoSgSv1BQyDdnk3067Sfkh64
+A5yf44BUjvJsSd/ViCVmCryoXU7KOMAdFkyRSiDDLQus6bZGEhc6f+VEikG+TZ2L
+xxY4OucE2Bz67S6ycyOUpXKo0+FW0juE6NTJdlYSXWOvfciZKA83h6yAej6MfUEu
+4orIvnCTVO7i3+hHybnSgftj42jrqqZzeXll8rkGHg4syrKRVaDD6qfJjgAHBJkJ
+pZT4zZwuJ1puWfBykI25S4mKUnk0erq4N5jpGqdm7U14fWBWCjZN85jY4WgZZOJx
+kBNO2NbmZKzZEzRGyMJ563z4l7MNfzZBHv+FeBNkX146J4ZhMbT8IXPGV9peNWqu
+mY2B9RhN4hlDrd3Hfz5uiiF3UGrFkDcsPRBHWGqQ20YpuOQNno7iL8N0FWauERw1
+dvxAGVwFfUznR3wc/eyGcnRhqQhlYPspukh0IVIyEbre3yVFSG/41GQYQfg08XYd
+LYiiDUu1i515/GeDvYN5VcnZ4nMhPgqfxW4rEUZjI86p++bqwqGy8eOCivkzGV3A
+IFWQwlvKKzU7tSdi3uHUq5v7xQsJrALdf67JVjCCGfUZa17O41vmm58L/vKhhL2Y
+mLz/H004DPsB+CtWoLwqZ8Jmb1EHwqNbna3tGHn3n63j2cV7gykZFa/zXeuBbbJ/
+t4ZIojIEzwAVKA9Xzcl3wyGCRr62WJPEcOqe4kBYREuKd22juPEm9RQgciIIj0tP
+eJVpD0QarGGzERsaq7pheAiWisO+Q4cLjF8Mb3/r89abnd4AQk6meabFJIE2dXWp
+LZy3I6FkNQ7L7LxNOILhnaWzWGdOBVwHeAAxfbLOzM22ewj7oUwBCRpsBJ8zl2PL
+VhUjX6N26YoiR9gE1RBaVrwRkYLmkyGvrowCDoZVPxvJqbfIESQE42zGB9DbEPNp
+WXCnzAg5cIjNC31We274yLE7dpNPVRXPJCRhtp7noorWVzDdKB+dFvg08bIir6Vj
+1gxy8DvuZE1Gq9vqx38V7Cy2MrSpsgapw5mli4n5cMafE7Ty3j5pBJFF2f3jUn6B
+7MjCrKp1d8v6MEy18J/Ugu1Lytb92LMcNtWBKmqyCSxekrUB9/FC2hWqOpdwRI6q
+QMWkwshjyEhmlr2PAkBPM4uVzUFc9lBw1GzOUChkr9jiINdbsUSRJrwZ32Nc3gRY
+yKzWbEELPSgRcXwXgH3QqZukvmk2tBMTIxilXqKTLmd7t/AEnIhkbqC0pfnyChyU
+YlFkme0RpAXpgbDJgv+Vk+1/1s6gyaNSzT4s2Q340WIO
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/lib/public_key/test/pbe_SUITE_data/pbes2_aes_256_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_256_enc_key.pem
new file mode 100644
index 0000000000..050337aead
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_256_enc_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI4MxgpDiHxQcCAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBA2g/L8XmlK2axDkeYJCltnBIIE
+0C3+NQ93DzEK/9qicy1sj0Vag1M7AeJjTGGpatETCxM+eHjk4kNNeDeMV5+EmCSu
+Db4P48uvHOBGGCcqdjnQovfQsAh81GWxgF3yqpd4OKn2RubMLO4/Qu+zGtt/XRKz
+T0pyHHBu6hyPSOhad2SIjKWuaHepwxGYaejLP83sy6yhm0sEmyBUn4nGSTOROcqR
+wd7EbwU2PYUcrRGGxtChU7MUNt48wBO50Xmri1ssPPtZV6MHio4IoIz4hqzCjvAc
+VE1BqAvNIJ7icpdnL8Jqq0lfwEmGjFCkAjgov5fNW9I1b44jE2Tv5LM2urMH8InQ
+9qNjTHozYQhHAk9nX4cmMgHsIhkOd7Z2M+nz8Hd1tj9DmBNOr5XbfyctgVntaMB4
+GGnThuNlX8d5giOKOcaNPMpLU1jtfDcb73mEhwCYcdo1PM0rjrYZ7qetjXJW/oHs
+Nl/hIZIRpMuCRVuXHml4G+ziKbMnXUN8sbtvgkQatYFHFQOhAqZeyzWp8SlDcfqb
+Zt0LlZVJEhKUYzZgKoe7SmR1rXTTCfYeB75PddyYwVgf/IkT6HJ/y1apGOP6/UJ8
+7UV6zssQA35gMsYDT36sH2hAQvA/cOFxSxrip0gm0xXOeFF0gbyZWbFqk0aULaeF
+rbBoMe28akxdE4eD06b+TP2NguUGP72l3TPOlG4PQVScweMw9L3oPXOVj4Vbbd0y
+DenNvRHlWIwOh/y7ADTHSWq9CE45QDBvFaTcn43JQWD8xCmhAhI/9H+fhAQUhABm
+P5QoJLE2IGo8A+Gi7rfgYQb3fCgqcn8azsRJzozhE+oXxMvxEESejYTtm26FNmLg
+ONTWysF9BiaKHt2IXwRX97691wZqv5wJEaxeeJxfVQ6MlAHoEDXe49VxGN4zFXuq
+Yb71JdQDgM94jwc/PoUwFH2ALSkIciiKwU0xfFpptycl4qWpy9m7QTIKw0DjgCfg
+MuySPRGM5jn3yVg72ux2Qf9MKNEybWjZ+Se9MJ1IZmZK5eOo6L2JsFCc0nRn908E
+vn4gAgUfMxyCZ1ygXfxINVAixR+6KPHsz1QTIxTZkrlnXRsuEu1ZfBSHzmXESvJo
+3I9PkP/Iekg1FBpB5xxd7mXwCj17EWqYXWsLnfd8SblMjRYd64q7hfx0oU/MJ1wi
+KadkGcyAGVRyleJRBR0LleYj/2sDihrRQY4zu5UtzSMFMH0XWjSWk5+ZQb+z3iDc
+Ud4GHcHiuTMH+i03ApZGWLN9v93za/15fsnZogstgJkaHxizTz5JuCkRf15xd8+O
+EH77Tsfizjp+h2NF/wcr4OSD0i+H0mwZWajpZ3UmSeJ0BFK6ODEbmVycrInpHo3n
+zyMJnEDTJXL3HUwZSLjO5e5cNaB+75tdHrj2yJtRLuaJFr02b0EO1MUYfuUuqlK4
+7mg7FkBsimW+CXkoLRjHYK88ibT3G+rZ/STf4S/jxiRjBi06FAql3H02K5i1umgB
+0BaaQei0Z8wQxMeTEnGzL+OcJeqDA1ZRFeXe7DNGsX1jeTYKPHA/Dr2IdZqyiCr2
+xh6e7RJuUe4D2liXW8LlMdwhN/7xSinA031PgBmb8XzSRmfdHhytFkA8PiM5T2ew
+NR3qXBJ/G7BuRa/t26RuKI3BMVoBQPhGx80ds10uJjxq
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 9e7f6851c9..dea78a876f 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -357,7 +357,7 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
CertDbHandle, CertDbRef)
end
catch
- error:{badmatch,{asn1, Asn1Reason}} ->
+ error:{badmatch,{error, {asn1, Asn1Reason}}} ->
%% ASN-1 decode of certificate somehow failed
?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, {failed_to_decode_certificate, Asn1Reason});
error:OtherReason ->
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index b88c7292a7..ae05a1f873 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -290,8 +290,7 @@ handle_protocol_record(#ssl_tls{type = ?HANDSHAKE, fragment = Data},
_ ->
HsEnv = State#state.handshake_env,
{next_state, StateName,
- State#state{protocol_buffers = Buffers,
- handshake_env =
+ State#state{handshake_env =
HsEnv#handshake_env{unprocessed_handshake_events
= unprocessed_events(Events)}}, Events}
end
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index e89104a999..653a8d58bd 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -89,7 +89,8 @@ tests() ->
critical_extension_verify_server,
critical_extension_verify_none,
customize_hostname_check,
- incomplete_chain
+ incomplete_chain,
+ long_chain
].
error_handling_tests()->
@@ -1156,6 +1157,44 @@ incomplete_chain(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+long_chain() ->
+ [{doc,"Test option verify_peer"}].
+long_chain(Config) when is_list(Config) ->
+ #{server_config := ServerConf,
+ client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(3)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(4)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(5)}]},
+ client_chain => #{root => [{key, ssl_test_lib:hardcode_rsa_key(3)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(1)}]}}),
+ [ServerRoot| _] = ServerCas = proplists:get_value(cacerts, ServerConf),
+ ClientCas = proplists:get_value(cacerts, ClientConf),
+
+ Active = proplists:get_value(active, Config),
+ ReceiveFunction = proplists:get_value(receive_function, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active}, {verify, verify_peer},
+ {cacerts, [ServerRoot]} |
+ proplists:delete(cacerts, ServerConf)]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active},
+ {verify, verify_peer},
+ {depth, 5},
+ {cacerts, ServerCas ++ ClientCas} |
+ proplists:delete(cacerts, ClientConf)]}]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index ffc02febdc..96b6ea338a 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -462,7 +462,9 @@ find_upper(Lower, Term, T, Dl, Dd, D, RF, Enc, Str) ->
case If of
{_, _, _Dots=0, _} -> % even if Len > T
If;
- {_, Len, _, _} when Len =< T, D1 < D orelse D < 0 ->
+ {_, _Len=T, _, _} -> % increasing the depth is meaningless
+ If;
+ {_, Len, _, _} when Len < T, D1 < D orelse D < 0 ->
find_upper(If, Term, T, D1, Dd2, D, RF, Enc, Str);
_ ->
search_depth(Lower, If, Term, T, Dl, D1, RF, Enc, Str)
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index 7796da66b8..4ad28b6169 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -32,7 +32,7 @@
io_with_huge_message_queue/1, format_string/1,
maps/1, coverage/1, otp_14178_unicode_atoms/1, otp_14175/1,
otp_14285/1, limit_term/1, otp_14983/1, otp_15103/1, otp_15076/1,
- otp_15159/1, otp_15639/1, otp_15847/1]).
+ otp_15159/1, otp_15639/1, otp_15847/1, otp_15875/1]).
-export([pretty/2, trf/3]).
@@ -65,7 +65,7 @@ all() ->
io_lib_width_too_small, io_with_huge_message_queue,
format_string, maps, coverage, otp_14178_unicode_atoms, otp_14175,
otp_14285, limit_term, otp_14983, otp_15103, otp_15076, otp_15159,
- otp_15639, otp_15847].
+ otp_15639, otp_15847, otp_15875].
%% Error cases for output.
error_1(Config) when is_list(Config) ->
@@ -2686,3 +2686,7 @@ otp_15847(_Config) ->
"{someRecord,<<...>>,...}" =
pretty(T, [{chars_limit,20}, {encoding,latin1}]),
ok.
+
+otp_15875(_Config) ->
+ S = io_lib:format("~tp", [[{0, [<<"00">>]}]], [{chars_limit, 18}]),
+ "[{0,[<<48,...>>]}]" = lists:flatten(S).