aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/doc/src/notes.xml46
-rw-r--r--lib/ssl/doc/src/standards_compliance.xml8
-rw-r--r--lib/ssl/src/dtls_connection.erl9
-rw-r--r--lib/ssl/src/dtls_packet_demux.erl6
-rw-r--r--lib/ssl/src/dtls_record.erl87
-rw-r--r--lib/ssl/src/ssl.erl14
-rw-r--r--lib/ssl/src/ssl_alert.erl31
-rw-r--r--lib/ssl/src/ssl_connection.erl74
-rw-r--r--lib/ssl/src/ssl_connection.hrl3
-rw-r--r--lib/ssl/src/ssl_handshake.erl12
-rw-r--r--lib/ssl/src/tls_connection.erl3
-rw-r--r--lib/ssl/src/tls_connection_1_3.erl4
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl166
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl232
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl52
-rw-r--r--lib/ssl/test/ssl_test_lib.erl67
-rw-r--r--lib/ssl/vsn.mk2
17 files changed, 584 insertions, 232 deletions
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 01cd630668..6af5a500b5 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -27,6 +27,36 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 9.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Returned "alert error string" is now same as logged alert
+ string</p>
+ <p>
+ Own Id: OTP-15844</p>
+ </item>
+ <item>
+ <p>
+ Fix returned extension map fields to follow the
+ documentation.</p>
+ <p>
+ Own Id: OTP-15862 Aux Id: ERL-951 </p>
+ </item>
+ <item>
+ <p>
+ Avoid DTLS crash due to missing gen_server return value
+ in DTLS packet demux process.</p>
+ <p>
+ Own Id: OTP-15864 Aux Id: ERL-962 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 9.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -119,6 +149,22 @@
</section>
+<section><title>SSL 9.2.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Returned "alert error string" is now same as logged alert
+ string</p>
+ <p>
+ Own Id: OTP-15844</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 9.2.3.1</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 3bd86178c8..3a472d4776 100644
--- a/lib/ssl/doc/src/standards_compliance.xml
+++ b/lib/ssl/doc/src/standards_compliance.xml
@@ -340,8 +340,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -479,8 +479,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 6928d7a93d..b220691e79 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -836,9 +836,12 @@ initial_flight_state(_) ->
next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{
dtls_record_buffer = Buf0,
dtls_cipher_texts = CT0} = Buffers,
+ connection_env = #connection_env{negotiated_version = Version},
+ static_env = #static_env{data_tag = DataTag},
ssl_options = SslOpts} = State0) ->
case dtls_record:get_dtls_records(Data,
- acceptable_record_versions(StateName, State0),
+ {DataTag, StateName, Version,
+ [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS]},
Buf0, SslOpts) of
{Records, Buf1} ->
CT1 = CT0 ++ Records,
@@ -849,10 +852,6 @@ next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{
Alert
end.
-acceptable_record_versions(hello, _) ->
- [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS];
-acceptable_record_versions(_, #state{connection_env = #connection_env{negotiated_version = Version}}) ->
- [Version].
dtls_handshake_events(Packets) ->
lists:map(fun(Packet) ->
diff --git a/lib/ssl/src/dtls_packet_demux.erl b/lib/ssl/src/dtls_packet_demux.erl
index c6431b55a9..94b350eaa5 100644
--- a/lib/ssl/src/dtls_packet_demux.erl
+++ b/lib/ssl/src/dtls_packet_demux.erl
@@ -154,9 +154,9 @@ handle_info({Transport, Socket, IP, InPortNo, _} = Msg, #state{listener = Socket
handle_info({PassiveTag, Socket},
#state{active_n = N,
listener = Socket,
- transport = {_,_,_, udp_error, PassiveTag}}) ->
- next_datagram(Socket, N);
-
+ transport = {_, _, _, _, PassiveTag}} = State) ->
+ next_datagram(Socket, N),
+ {noreply, State};
%% UDP socket does not have a connection and should not receive an econnreset
%% This does however happens on some windows versions. Just ignoring it
%% appears to make things work as expected!
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index a4846f42c5..8b8db7b2de 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -162,26 +162,16 @@ current_connection_state_epoch(#{current_write := #{epoch := Epoch}},
Epoch.
%%--------------------------------------------------------------------
--spec get_dtls_records(binary(), [ssl_record:ssl_version()], binary(),
+-spec get_dtls_records(binary(), {atom(), atom(), ssl_record:ssl_version(), [ssl_record:ssl_version()]}, binary(),
#ssl_options{}) -> {[binary()], binary()} | #alert{}.
%%
%% Description: Given old buffer and new data from UDP/SCTP, packs up a records
%% and returns it as a list of tls_compressed binaries also returns leftover
%% data
%%--------------------------------------------------------------------
-get_dtls_records(Data, Versions, Buffer, SslOpts) ->
+get_dtls_records(Data, Vinfo, Buffer, SslOpts) ->
BinData = list_to_binary([Buffer, Data]),
- case erlang:byte_size(BinData) of
- N when N >= 3 ->
- case assert_version(BinData, Versions) of
- true ->
- get_dtls_records_aux(BinData, [], SslOpts);
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
- end;
- _ ->
- get_dtls_records_aux(BinData, [], SslOpts)
- end.
+ get_dtls_records_aux(Vinfo, BinData, [], SslOpts).
%%====================================================================
%% Encoding DTLS records
@@ -405,52 +395,49 @@ initial_connection_state(ConnectionEnd, BeastMitigation) ->
client_verify_data => undefined,
server_verify_data => undefined
}.
-assert_version(<<?BYTE(_), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>>, Versions) ->
- is_acceptable_version({MajVer, MinVer}, Versions).
-get_dtls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Epoch), ?UINT48(SequenceNumber),
- ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
- Acc, SslOpts) ->
- ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
- get_dtls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
- version = {MajVer, MinVer},
- epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc], SslOpts);
-get_dtls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Epoch), ?UINT48(SequenceNumber),
- ?UINT16(Length),
- Data:Length/binary, Rest/binary>> = RawDTLSRecord,
- Acc, SslOpts) when MajVer >= 128 ->
- ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
- get_dtls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
- version = {MajVer, MinVer},
- epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc], SslOpts);
-get_dtls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Epoch), ?UINT48(SequenceNumber),
- ?UINT16(Length), Data:Length/binary,
- Rest/binary>> = RawDTLSRecord, Acc, SslOpts) ->
+get_dtls_records_aux({DataTag, StateName, _, Versions} = Vinfo, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Epoch), ?UINT48(SequenceNumber),
+ ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
+ Acc, SslOpts) when ((StateName == hello) orelse
+ ((StateName == certify) andalso (DataTag == udp)) orelse
+ ((StateName == abbreviated) andalso(DataTag == udp)))
+ andalso
+ ((Type == ?HANDSHAKE) orelse
+ (Type == ?ALERT)) ->
ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
- get_dtls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
- version = {MajVer, MinVer},
- epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc], SslOpts);
-get_dtls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
+ case is_acceptable_version({MajVer, MinVer}, Versions) of
+ true ->
+ get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type,
+ version = {MajVer, MinVer},
+ epoch = Epoch, sequence_number = SequenceNumber,
+ fragment = Data} | Acc], SslOpts);
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end;
+get_dtls_records_aux({_, _, Version, _} = Vinfo, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
- Acc, SslOpts) ->
+ Acc, SslOpts) when (Type == ?APPLICATION_DATA) orelse
+ (Type == ?HANDSHAKE) orelse
+ (Type == ?ALERT) orelse
+ (Type == ?CHANGE_CIPHER_SPEC) ->
ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
- get_dtls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
- version = {MajVer, MinVer},
- epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc], SslOpts);
-get_dtls_records_aux(<<?BYTE(_), ?BYTE(_MajVer), ?BYTE(_MinVer),
+ case {MajVer, MinVer} of
+ Version ->
+ get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type,
+ version = {MajVer, MinVer},
+ epoch = Epoch, sequence_number = SequenceNumber,
+ fragment = Data} | Acc], SslOpts);
+ _ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end;
+get_dtls_records_aux(_, <<?BYTE(_), ?BYTE(_MajVer), ?BYTE(_MinVer),
?UINT16(Length), _/binary>>,
_Acc, _) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
-get_dtls_records_aux(Data, Acc, _) ->
+get_dtls_records_aux(_, Data, Acc, _) ->
case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
true ->
{lists:reverse(Acc), Data};
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 6af65e09f2..20b1e85ceb 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -125,7 +125,10 @@
protocol_extensions/0,
session_id/0,
error_alert/0,
- srp_param_type/0]).
+ tls_alert/0,
+ srp_param_type/0,
+ named_curve/0,
+ sign_scheme/0]).
%% -------------------------------------------------------------------------------------------------------
@@ -191,7 +194,8 @@
| rsa_pss_pss_sha384
| rsa_pss_pss_sha512
| rsa_pkcs1_sha1
- | ecdsa_sha1.
+ | ecdsa_sha1. % exported
+
-type kex_algo() :: rsa |
dhe_rsa | dhe_dss |
ecdhe_ecdsa | ecdh_ecdsa | ecdh_rsa |
@@ -236,7 +240,7 @@
sect163r2 |
secp160k1 |
secp160r1 |
- secp160r2.
+ secp160r2. % exported
-type group() :: secp256r1 | secp384r1 | secp521r1 | ffdhe2048 |
ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192.
@@ -279,7 +283,7 @@
bad_certificate_status_response |
bad_certificate_hash_value |
unknown_psk_identity |
- no_application_protocol.
+ no_application_protocol. % exported
%% -------------------------------------------------------------------------------------------------------
-type common_option() :: {protocol, protocol()} |
@@ -1909,7 +1913,7 @@ validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
handle_cb_info({V1, V2, V3, V4}, {_,_,_,_,_}) ->
- {V1,V2,V3,V4, list_to_atom(atom_to_list(V2) ++ "passive")};
+ {V1,V2,V3,V4, list_to_atom(atom_to_list(V2) ++ "_passive")};
handle_cb_info(CbInfo, _) ->
CbInfo.
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 06b1b005a5..2d57b72f7b 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -32,7 +32,11 @@
-include("ssl_record.hrl").
-include("ssl_internal.hrl").
--export([decode/1, own_alert_txt/1, alert_txt/1, reason_code/2]).
+-export([decode/1,
+ own_alert_txt/1,
+ alert_txt/1,
+ alert_txt/4,
+ reason_code/4]).
%%====================================================================
%% Internal application API
@@ -48,20 +52,29 @@ decode(Bin) ->
decode(Bin, [], 0).
%%--------------------------------------------------------------------
-%% -spec reason_code(#alert{}, client | server) ->
-%% {tls_alert, unicode:chardata()} | closed.
-%-spec reason_code(#alert{}, client | server) -> closed | {essl, string()}.
+-spec reason_code(#alert{}, client | server, ProtocolName::string(), StateName::atom()) ->
+ {tls_alert, {atom(), unicode:chardata()}} | closed.
%%
%% Description: Returns the error reason that will be returned to the
%% user.
%%--------------------------------------------------------------------
-reason_code(#alert{description = ?CLOSE_NOTIFY}, _) ->
+reason_code(#alert{description = ?CLOSE_NOTIFY}, _, _, _) ->
closed;
-reason_code(#alert{description = Description, role = Role} = Alert, Role) ->
- {tls_alert, {description_atom(Description), own_alert_txt(Alert)}};
-reason_code(#alert{description = Description} = Alert, Role) ->
- {tls_alert, {description_atom(Description), alert_txt(Alert#alert{role = Role})}}.
+reason_code(#alert{description = Description, role = Role} = Alert, Role, ProtocolName, StateName) ->
+ Txt = lists:flatten(alert_txt(ProtocolName, Role, StateName, own_alert_txt(Alert))),
+ {tls_alert, {description_atom(Description), Txt}};
+reason_code(#alert{description = Description} = Alert, Role, ProtocolName, StateName) ->
+ Txt = lists:flatten(alert_txt(ProtocolName, Role, StateName, alert_txt(Alert))),
+ {tls_alert, {description_atom(Description), Txt}}.
+
+%%--------------------------------------------------------------------
+-spec alert_txt(string(), server | client, StateNam::atom(), string()) -> string().
+%%
+%% Description: Generates alert text for log or string part of error return.
+%%--------------------------------------------------------------------
+alert_txt(ProtocolName, Role, StateName, Txt) ->
+ io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]).
%%--------------------------------------------------------------------
-spec own_alert_txt(#alert{}) -> string().
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 345db7510f..cc4d60389e 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -124,7 +124,7 @@ handshake(#sslsocket{pid = [Pid|_]} = Socket, Timeout) ->
connected ->
{ok, Socket};
{ok, Ext} ->
- {ok, Socket, Ext};
+ {ok, Socket, no_records(Ext)};
Error ->
Error
end.
@@ -328,34 +328,33 @@ prf(ConnectionPid, Secret, Label, Seed, WantedLength) ->
%%====================================================================
%% Alert and close handling
%%====================================================================
-handle_own_alert(Alert, _, StateName,
+handle_own_alert(Alert0, _, StateName,
#state{static_env = #static_env{role = Role,
protocol_cb = Connection},
ssl_options = SslOpts} = State) ->
try %% Try to tell the other side
- send_alert(Alert, StateName, State)
+ send_alert(Alert0, StateName, State)
catch _:_ -> %% Can crash if we are in a uninitialized state
ignore
end,
try %% Try to tell the local user
- log_alert(SslOpts#ssl_options.log_level, Role,
- Connection:protocol_name(), StateName,
- Alert#alert{role = Role}),
+ Alert = Alert0#alert{role = Role},
+ log_alert(SslOpts#ssl_options.log_level, Role, Connection:protocol_name(), StateName, Alert),
handle_normal_shutdown(Alert,StateName, State)
catch _:_ ->
ok
end,
{stop, {shutdown, own_alert}, State}.
-handle_normal_shutdown(Alert, _, #state{static_env = #static_env{role = Role,
- socket = Socket,
- transport_cb = Transport,
- protocol_cb = Connection,
- tracker = Tracker},
- handshake_env = #handshake_env{renegotiation = {false, first}},
- start_or_recv_from = StartFrom} = State) ->
+handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = Role,
+ socket = Socket,
+ transport_cb = Transport,
+ protocol_cb = Connection,
+ tracker = Tracker},
+ handshake_env = #handshake_env{renegotiation = {false, first}},
+ start_or_recv_from = StartFrom} = State) ->
Pids = Connection:pids(State),
- alert_user(Pids, Transport, Tracker,Socket, StartFrom, Alert, Role, Connection);
+ alert_user(Pids, Transport, Tracker,Socket, StartFrom, Alert, Role, StateName, Connection);
handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = Role,
socket = Socket,
@@ -366,9 +365,9 @@ handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role =
socket_options = Opts,
start_or_recv_from = RecvFrom} = State) ->
Pids = Connection:pids(State),
- alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection).
+ alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, StateName, Connection).
-handle_alert(#alert{level = ?FATAL} = Alert, StateName,
+handle_alert(#alert{level = ?FATAL} = Alert0, StateName,
#state{static_env = #static_env{role = Role,
socket = Socket,
host = Host,
@@ -382,11 +381,11 @@ handle_alert(#alert{level = ?FATAL} = Alert, StateName,
session = Session,
socket_options = Opts} = State) ->
invalidate_session(Role, Host, Port, Session),
+ Alert = Alert0#alert{role = opposite_role(Role)},
log_alert(SslOpts#ssl_options.log_level, Role, Connection:protocol_name(),
- StateName, Alert#alert{role = opposite_role(Role)}),
+ StateName, Alert),
Pids = Connection:pids(State),
- alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert,
- opposite_role(Role), Connection),
+ alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role, StateName, Connection),
{stop, {shutdown, normal}, State};
handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
@@ -396,13 +395,14 @@ handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
StateName, State) ->
handle_normal_shutdown(Alert, StateName, State),
{stop,{shutdown, peer_close}, State};
-handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
+handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert0, StateName,
#state{static_env = #static_env{role = Role,
protocol_cb = Connection},
handshake_env = #handshake_env{renegotiation = {true, internal}},
ssl_options = SslOpts} = State) ->
+ Alert = Alert0#alert{role = opposite_role(Role)},
log_alert(SslOpts#ssl_options.log_level, Role,
- Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
+ Connection:protocol_name(), StateName, Alert),
handle_normal_shutdown(Alert, StateName, State),
{stop,{shutdown, peer_close}, State};
@@ -709,6 +709,7 @@ handle_session(#server_hello{cipher_suite = CipherSuite,
{ExpectNPN, Protocol} = case Protocol0 of
undefined ->
+
{false, CurrentProtocol};
_ ->
{ProtoExt =:= npn, Protocol0}
@@ -1445,7 +1446,7 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName,
} = State) when StateName =/= connection ->
Pids = Connection:pids(State),
alert_user(Pids, Transport, Tracker,Socket,
- StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, Connection),
+ StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, StateName, Connection),
{stop, {shutdown, normal}, State};
handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_env{socket = Socket,
@@ -2907,22 +2908,22 @@ send_user(Pid, Msg) ->
Pid ! Msg,
ok.
-alert_user(Pids, Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, Connection) ->
- alert_user(Pids, Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, Connection);
-alert_user(Pids, Transport, Tracker, Socket,_, _, _, From, Alert, Role, Connection) ->
- alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection).
+alert_user(Pids, Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, StateName, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, StateName, Connection);
+alert_user(Pids, Transport, Tracker, Socket,_, _, _, From, Alert, Role, StateName, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, StateName, Connection).
-alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection) ->
- alert_user(Pids, Transport, Tracker, Socket, false, no_pid, From, Alert, Role, Connection).
+alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, StateName, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, false, no_pid, From, Alert, Role, StateName, Connection).
-alert_user(_, _, _, _, false = Active, Pid, From, Alert, Role, _) when From =/= undefined ->
+alert_user(_, _, _, _, false = Active, Pid, From, Alert, Role, StateName, Connection) when From =/= undefined ->
%% If there is an outstanding ssl_accept | recv
%% From will be defined and send_or_reply will
%% send the appropriate error message.
- ReasonCode = ssl_alert:reason_code(Alert, Role),
+ ReasonCode = ssl_alert:reason_code(Alert, Role, Connection:protocol_name(), StateName),
send_or_reply(Active, Pid, From, {error, ReasonCode});
-alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connection) ->
- case ssl_alert:reason_code(Alert, Role) of
+alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, StateName, Connection) ->
+ case ssl_alert:reason_code(Alert, Role, Connection:protocol_name(), StateName) of
closed ->
send_or_reply(Active, Pid, From,
{ssl_closed, Connection:socket(Pids, Transport, Socket, Tracker)});
@@ -2933,11 +2934,11 @@ alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Con
log_alert(Level, Role, ProtocolName, StateName, #alert{role = Role} = Alert) ->
Txt = ssl_alert:own_alert_txt(Alert),
- Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]),
+ Report = ssl_alert:alert_txt(ProtocolName, Role, StateName, Txt),
ssl_logger:notice(Level, Report);
log_alert(Level, Role, ProtocolName, StateName, Alert) ->
Txt = ssl_alert:alert_txt(Alert),
- Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]),
+ Report = ssl_alert:alert_txt(ProtocolName, Role, StateName, Txt),
ssl_logger:notice(Level, Report).
invalidate_session(client, Host, Port, Session) ->
@@ -3000,3 +3001,8 @@ new_emulated([], EmOpts) ->
EmOpts;
new_emulated(NewEmOpts, _) ->
NewEmOpts.
+
+no_records(Extensions) ->
+ maps:map(fun(_, Value) ->
+ ssl_handshake:extension_value(Value)
+ end, Extensions).
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index ff7207a8ce..844368c761 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -66,6 +66,7 @@
sni_hostname = undefined,
expecting_next_protocol_negotiation = false ::boolean(),
next_protocol = undefined :: undefined | binary(),
+ alpn = undefined, %% Used in TLS 1.3
negotiated_protocol,
hashsign_algorithm = {undefined, undefined},
cert_hashsign_algorithm = {undefined, undefined},
@@ -76,7 +77,7 @@
srp_params :: #srp_user{} | secret_printout() | 'undefined',
public_key_info :: ssl_handshake:public_key_info() | 'undefined',
premaster_secret :: binary() | secret_printout() | 'undefined',
- server_psk_identity :: binary() | 'undefined' % server psk identity hint
+ server_psk_identity :: binary() | 'undefined' % server psk identity hint
}).
-record(connection_env, {
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index b51ba0fa2d..1f0c95701b 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -76,7 +76,8 @@
handle_client_hello_extensions/9, %% Returns server hello extensions
handle_server_hello_extensions/9, select_curve/2, select_curve/3,
select_hashsign/4, select_hashsign/5,
- select_hashsign_algs/3, empty_extensions/2, add_server_share/3
+ select_hashsign_algs/3, empty_extensions/2, add_server_share/3,
+ add_alpn/2, add_selected_version/1, decode_alpn/1
]).
-export([get_cert_params/1,
@@ -363,7 +364,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 ->
@@ -1165,6 +1166,13 @@ add_server_share(hello_retry_request, Extensions,
Extensions#{key_share => #key_share_hello_retry_request{
selected_group = Group}}.
+add_alpn(Extensions, ALPN0) ->
+ ALPN = encode_alpn([ALPN0], false),
+ Extensions#{alpn => ALPN}.
+
+add_selected_version(Extensions) ->
+ SupportedVersions = #server_hello_selected_version{selected_version = {3,4}},
+ Extensions#{server_hello_selected_version => SupportedVersions}.
kse_remove_private_key(#key_share_entry{
group = Group,
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 2651fc09bd..dabc2f8ec8 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -317,8 +317,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/src/tls_connection_1_3.erl b/lib/ssl/src/tls_connection_1_3.erl
index 821b7000cc..117e4f059d 100644
--- a/lib/ssl/src/tls_connection_1_3.erl
+++ b/lib/ssl/src/tls_connection_1_3.erl
@@ -228,8 +228,8 @@ wait_cert_cr(internal, #change_cipher_spec{}, State, _Module) ->
tls_connection:next_event(?FUNCTION_NAME, no_record, State);
wait_cert_cr(internal, #certificate_1_3{} = Certificate, State0, _Module) ->
case tls_handshake_1_3:do_wait_cert_cr(Certificate, State0) of
- #alert{} = Alert ->
- ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert_cr, State0);
+ {#alert{} = Alert, State} ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert_cr, State);
{State1, NextState} ->
tls_connection:next_event(NextState, no_record, State1)
end;
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index 12ab2015aa..4de51c9a35 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -39,8 +39,7 @@
%% Create handshake messages
-export([certificate/5,
certificate_verify/4,
- encrypted_extensions/0,
- server_hello/4]).
+ encrypted_extensions/0]).
-export([do_start/2,
do_negotiated/2,
@@ -62,10 +61,10 @@
%% Create handshake messages
%%====================================================================
-server_hello(MsgType, SessionId, KeyShare, ConnectionStates) ->
+server_hello(MsgType, SessionId, KeyShare, ConnectionStates, ALPN) ->
#{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates, read),
- Extensions = server_hello_extensions(MsgType, KeyShare),
+ Extensions = server_hello_extensions(MsgType, KeyShare, ALPN),
#server_hello{server_version = {3,3}, %% legacy_version
cipher_suite = SecParams#security_parameters.cipher_suite,
compression_method = 0, %% legacy attribute
@@ -74,10 +73,26 @@ server_hello(MsgType, SessionId, KeyShare, ConnectionStates) ->
extensions = Extensions
}.
-server_hello_extensions(MsgType, KeyShare) ->
+%% The server's extensions MUST contain "supported_versions".
+%% Additionally, it SHOULD contain the minimal set of extensions
+%% necessary for the client to generate a correct ClientHello pair. As
+%% with the ServerHello, a HelloRetryRequest MUST NOT contain any
+%% extensions that were not first offered by the client in its
+%% ClientHello, with the exception of optionally the "cookie" (see
+%% Section 4.2.2) extension.
+server_hello_extensions(hello_retry_request = MsgType, KeyShare, _) ->
SupportedVersions = #server_hello_selected_version{selected_version = {3,4}},
Extensions = #{server_hello_selected_version => SupportedVersions},
- ssl_handshake:add_server_share(MsgType, Extensions, KeyShare).
+ ssl_handshake:add_server_share(MsgType, Extensions, KeyShare);
+server_hello_extensions(MsgType, KeyShare, undefined) ->
+ SupportedVersions = #server_hello_selected_version{selected_version = {3,4}},
+ Extensions = #{server_hello_selected_version => SupportedVersions},
+ ssl_handshake:add_server_share(MsgType, Extensions, KeyShare);
+server_hello_extensions(MsgType, KeyShare, ALPN0) ->
+ Extensions0 = ssl_handshake:add_selected_version(#{}), %% {3,4} (TLS 1.3)
+ Extensions1 = ssl_handshake:add_alpn(Extensions0, ALPN0),
+ ssl_handshake:add_server_share(MsgType, Extensions1, KeyShare).
+
server_hello_random(server_hello, #security_parameters{server_random = Random}) ->
Random;
@@ -469,7 +484,8 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
#state{connection_states = _ConnectionStates0,
ssl_options = #ssl_options{ciphers = ServerCiphers,
signature_algs = ServerSignAlgs,
- supported_groups = ServerGroups0},
+ supported_groups = ServerGroups0,
+ alpn_preferred_protocols = ALPNPreferredProtocols},
session = #session{own_certificate = Cert}} = State0) ->
ClientGroups0 = maps:get(elliptic_curves, Extensions, undefined),
ClientGroups = get_supported_groups(ClientGroups0),
@@ -478,6 +494,9 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
ClientShares0 = maps:get(key_share, Extensions, undefined),
ClientShares = get_key_shares(ClientShares0),
+ ClientALPN0 = maps:get(alpn, Extensions, undefined),
+ ClientALPN = ssl_handshake:decode_alpn(ClientALPN0),
+
ClientSignAlgs = get_signature_scheme_list(
maps:get(signature_algs, Extensions, undefined)),
ClientSignAlgsCert = get_signature_scheme_list(
@@ -486,6 +505,9 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
{Ref,Maybe} = maybe(),
try
+ %% Handle ALPN extension if ALPN is configured
+ ALPNProtocol = Maybe(handle_alpn(ALPNPreferredProtocols, ClientALPN)),
+
%% If the server does not select a PSK, then the server independently selects a
%% cipher suite, an (EC)DHE group and key share for key establishment,
%% and a signature algorithm/certificate pair to authenticate itself to
@@ -511,8 +533,14 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
%% Generate server_share
KeyShare = ssl_cipher:generate_server_share(Group),
- State1 = update_start_state(State0, Cipher, KeyShare, SessionId,
- Group, SelectedSignAlg, ClientPubKey),
+ State1 = update_start_state(State0,
+ #{cipher => Cipher,
+ key_share => KeyShare,
+ session_id => SessionId,
+ group => Group,
+ sign_alg => SelectedSignAlg,
+ peer_public_key => ClientPubKey,
+ alpn => ALPNProtocol}),
%% 4.1.4. Hello Retry Request
%%
@@ -522,10 +550,7 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
%% the handshake.
Maybe(send_hello_retry_request(State1, ClientPubKey, KeyShare, SessionId))
- %% TODO:
- %% - session handling
- %% - handle extensions: ALPN
- %% (do not handle: NPN, srp, renegotiation_info, ec_point_formats)
+ %% TODO: session handling
catch
{Ref, {insufficient_security, no_suitable_groups}} ->
@@ -537,7 +562,9 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
{Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
{Ref, {insufficient_security, no_suitable_public_key}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key);
+ {Ref, no_application_protocol} ->
+ ?ALERT_REC(?FATAL, ?NO_APPLICATION_PROTOCOL)
end;
%% TLS Client
do_start(#server_hello{cipher_suite = SelectedCipherSuite,
@@ -588,8 +615,11 @@ do_start(#server_hello{cipher_suite = SelectedCipherSuite,
HelloVersion = tls_record:hello_version(SslOpts#ssl_options.versions),
%% Update state
- State1 = update_start_state(State0, SelectedCipherSuite, ClientKeyShare, SessionId,
- SelectedGroup, undefined, undefined),
+ State1 = update_start_state(State0,
+ #{cipher => SelectedCipherSuite,
+ key_share => ClientKeyShare,
+ session_id => SessionId,
+ group => SelectedGroup}),
%% Replace ClientHello1 with a special synthetic handshake message
State2 = replace_ch1_with_message_hash(State1),
@@ -625,7 +655,8 @@ do_negotiated(start_handshake,
dh_public_value = ClientPublicKey},
ssl_options = #ssl_options{} = SslOpts,
key_share = KeyShare,
- handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
+ handshake_env = #handshake_env{tls_handshake_history = _HHistory0,
+ alpn = ALPN},
connection_env = #connection_env{private_key = CertPrivateKey},
static_env = #static_env{
cert_db = CertDbHandle,
@@ -640,7 +671,7 @@ do_negotiated(start_handshake,
try
%% Create server_hello
%% Extensions: supported_versions, key_share, (pre_shared_key)
- ServerHello = server_hello(server_hello, SessionId, KeyShare, ConnectionStates0),
+ ServerHello = server_hello(server_hello, SessionId, KeyShare, ConnectionStates0, ALPN),
{State1, _} = tls_connection:send_handshake(ServerHello, State0),
@@ -702,6 +733,8 @@ do_wait_cert(#certificate_1_3{} = Certificate, State0) ->
{?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason), State};
{Ref, {{handshake_failure, Reason}, State}} ->
{?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason), State};
+ {Ref, {#alert{} = Alert, State}} ->
+ {Alert, State};
{#alert{} = Alert, State} ->
{Alert, State}
end.
@@ -801,8 +834,12 @@ do_wait_sh(#server_hello{cipher_suite = SelectedCipherSuite,
{_, ClientPrivateKey} = get_client_private_key([SelectedGroup], ClientKeyShare),
%% Update state
- State1 = update_start_state(State0, SelectedCipherSuite, ClientKeyShare0, SessionId,
- SelectedGroup, undefined, ServerPublicKey),
+ State1 = update_start_state(State0,
+ #{cipher => SelectedCipherSuite,
+ key_share => ClientKeyShare0,
+ session_id => SessionId,
+ group => SelectedGroup,
+ peer_public_key => ServerPublicKey}),
State2 = calculate_handshake_secrets(ServerPublicKey, ClientPrivateKey, SelectedGroup, State1),
@@ -858,7 +895,9 @@ do_wait_cert_cr(#certificate_1_3{} = Certificate, State0) ->
{Ref, {{internal_error, Reason}, _State}} ->
?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason);
{Ref, {{handshake_failure, Reason}, _State}} ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason)
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason);
+ {Ref, {#alert{} = Alert, State}} ->
+ {Alert, State}
end;
do_wait_cert_cr(#certificate_request_1_3{} = CertificateRequest, State0) ->
{Ref,Maybe} = maybe(),
@@ -984,9 +1023,10 @@ compare_verify_data(_, _) ->
{error, decrypt_error}.
-send_hello_retry_request(#state{connection_states = ConnectionStates0} = State0,
+send_hello_retry_request(#state{connection_states = ConnectionStates0,
+ handshake_env = #handshake_env{alpn = ALPN}} = State0,
no_suitable_key, KeyShare, SessionId) ->
- ServerHello = server_hello(hello_retry_request, SessionId, KeyShare, ConnectionStates0),
+ ServerHello = server_hello(hello_retry_request, SessionId, KeyShare, ConnectionStates0, ALPN),
{State1, _} = tls_connection:send_handshake(ServerHello, State0),
%% Update handshake history
@@ -1076,13 +1116,11 @@ process_certificate(#certificate_1_3{certificate_list = Certs0},
State = store_peer_cert(State0, PeerCert, PublicKeyInfo),
{ok, {State, wait_cv}};
{error, Reason} ->
- State1 = calculate_traffic_secrets(State0),
- State = ssl_record:step_encryption_state(State1),
+ State = update_encryption_state(Role, State0),
{error, {Reason, State}};
- #alert{} = Alert ->
- State1 = calculate_traffic_secrets(State0),
- State = ssl_record:step_encryption_state(State1),
- {Alert, State}
+ {ok, #alert{} = Alert} ->
+ State = update_encryption_state(Role, State0),
+ {error, {Alert, State}}
end;
false ->
State1 = calculate_traffic_secrets(State0),
@@ -1106,6 +1144,17 @@ is_supported_signature_algorithm([BinCert|_], SignAlgs0) ->
lists:member(Scheme, SignAlgs).
+%% Sets correct encryption state when sending Alerts in shared states that use different secrets.
+%% - If client: use handshake secrets.
+%% - If server: use traffic secrets as by this time the client's state machine
+%% already stepped into the 'connection' state.
+update_encryption_state(server, State0) ->
+ State1 = calculate_traffic_secrets(State0),
+ ssl_record:step_encryption_state(State1);
+update_encryption_state(client, State) ->
+ State.
+
+
validate_certificate_chain(Certs, CertDbHandle, CertDbRef, SslOptions, CRLDbHandle, Role, Host) ->
ServerName = ssl_handshake:server_name(SslOptions#ssl_options.server_name_indication, Host, Role),
[PeerCert | ChainCerts ] = Certs,
@@ -1126,9 +1175,9 @@ validate_certificate_chain(Certs, CertDbHandle, CertDbRef, SslOptions, CRLDbHand
{ok, {PublicKeyInfo,_}} ->
{ok, {PeerCert, PublicKeyInfo}};
{error, Reason} ->
- ssl_handshake:handle_path_validation_error(Reason, PeerCert, ChainCerts,
- SslOptions, Options,
- CertDbHandle, CertDbRef)
+ {ok, ssl_handshake:handle_path_validation_error(Reason, PeerCert, ChainCerts,
+ SslOptions, Options,
+ CertDbHandle, CertDbRef)}
end
catch
error:{badmatch,{asn1, Asn1Reason}} ->
@@ -1337,11 +1386,24 @@ update_connection_state(ConnectionState = #{security_parameters := SecurityParam
cipher_state => cipher_init(Key, IV, FinishedKey)}.
+update_start_state(State, Map) ->
+ Cipher = maps:get(cipher, Map, undefined),
+ KeyShare = maps:get(key_share, Map, undefined),
+ SessionId = maps:get(session_id, Map, undefined),
+ Group = maps:get(group, Map, undefined),
+ SelectedSignAlg = maps:get(sign_alg, Map, undefined),
+ PeerPublicKey = maps:get(peer_public_key, Map, undefined),
+ ALPNProtocol = maps:get(alpn, Map, undefined),
+ update_start_state(State, Cipher, KeyShare, SessionId,
+ Group, SelectedSignAlg, PeerPublicKey,
+ ALPNProtocol).
+%%
update_start_state(#state{connection_states = ConnectionStates0,
+ handshake_env = #handshake_env{} = HsEnv,
connection_env = CEnv,
session = Session} = State,
Cipher, KeyShare, SessionId,
- Group, SelectedSignAlg, ClientPubKey) ->
+ Group, SelectedSignAlg, PeerPublicKey, ALPNProtocol) ->
#{security_parameters := SecParamsR0} = PendingRead =
maps:get(pending_read, ConnectionStates0),
#{security_parameters := SecParamsW0} = PendingWrite =
@@ -1352,11 +1414,12 @@ update_start_state(#state{connection_states = ConnectionStates0,
ConnectionStates0#{pending_read => PendingRead#{security_parameters => SecParamsR},
pending_write => PendingWrite#{security_parameters => SecParamsW}},
State#state{connection_states = ConnectionStates,
+ handshake_env = HsEnv#handshake_env{alpn = ALPNProtocol},
key_share = KeyShare,
session = Session#session{session_id = SessionId,
ecc = Group,
sign_alg = SelectedSignAlg,
- dh_public_value = ClientPubKey,
+ dh_public_value = PeerPublicKey,
cipher_suite = Cipher},
connection_env = CEnv#connection_env{negotiated_version = {3,4}}}.
@@ -1628,19 +1691,28 @@ get_server_public_key({key_share_entry, Group, PublicKey}) ->
{Group, PublicKey}.
-%% get_client_public_key(Group, ClientShares) ->
-%% case lists:keysearch(Group, 2, ClientShares) of
-%% {value, {_, _, ClientPublicKey}} ->
-%% ClientPublicKey;
-%% false ->
-%% %% 4.1.4. Hello Retry Request
-%% %%
-%% %% The server will send this message in response to a ClientHello
-%% %% message if it is able to find an acceptable set of parameters but the
-%% %% ClientHello does not contain sufficient information to proceed with
-%% %% the handshake.
-%% no_suitable_key
-%% end.
+%% RFC 7301 - Application-Layer Protocol Negotiation Extension
+%% It is expected that a server will have a list of protocols that it
+%% supports, in preference order, and will only select a protocol if the
+%% client supports it. In that case, the server SHOULD select the most
+%% highly preferred protocol that it supports and that is also
+%% advertised by the client. In the event that the server supports no
+%% protocols that the client advertises, then the server SHALL respond
+%% with a fatal "no_application_protocol" alert.
+handle_alpn(undefined, _) ->
+ {ok, undefined};
+handle_alpn([], _) ->
+ {error, no_application_protocol};
+handle_alpn([_|_], undefined) ->
+ {ok, undefined};
+handle_alpn([ServerProtocol|T], ClientProtocols) ->
+ case lists:member(ServerProtocol, ClientProtocols) of
+ true ->
+ {ok, ServerProtocol};
+ false ->
+ handle_alpn(T, ClientProtocols)
+ end.
+
select_cipher_suite([], _) ->
{error, no_suitable_cipher};
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 8cb98e7fa6..ce4479020e 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -164,6 +164,7 @@ api_tests() ->
prf,
socket_options,
active_n,
+ internal_active_1,
cipher_suites,
handshake_continue,
handshake_continue_timeout,
@@ -271,7 +272,11 @@ tls13_test_group() ->
tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client,
tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client,
tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client,
- tls13_connection_information].
+ tls13_connection_information,
+ tls13_ssl_server_with_alpn_ssl_client,
+ tls13_ssl_server_with_alpn_ssl_client_empty_alpn,
+ tls13_ssl_server_with_alpn_ssl_client_bad_alpn,
+ tls13_ssl_server_with_alpn_ssl_client_alpn].
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
@@ -500,6 +505,15 @@ init_per_testcase(accept_pool, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
Config
end;
+
+init_per_testcase(internal_active_1, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, internal_active_n, 1),
+ ssl:start(),
+ ct:timetrap({seconds, 5}),
+ Config;
+
init_per_testcase(controller_dies, Config) ->
ct:timetrap({seconds, 10}),
Config;
@@ -522,6 +536,10 @@ end_per_testcase(reuse_session_expired, Config) ->
application:unset_env(ssl, session_delay_cleanup_time),
end_per_testcase(default_action, Config);
+end_per_testcase(internal_active_n, Config) ->
+ application:unset_env(ssl, internal_active_n),
+ end_per_testcase(default_action, Config);
+
end_per_testcase(Case, Config) when Case == protocol_versions;
Case == empty_protocol_versions->
application:unset_env(ssl, protocol_versions),
@@ -1987,6 +2005,10 @@ recv_active_once(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+
+
+
%%--------------------------------------------------------------------
recv_active_n() ->
[{doc,"Test recv on active (n) socket"}].
@@ -2013,6 +2035,7 @@ recv_active_n(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
%%--------------------------------------------------------------------
%% Test case adapted from gen_tcp_misc_SUITE.
active_n() ->
@@ -2238,6 +2261,33 @@ upgrade_result(Socket) ->
ok
end.
+
+%%--------------------------------------------------------------------
+internal_active_1() ->
+ [{doc,"Test internal active 1 (behave as internal active once)"}].
+
+internal_active_1(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, 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, send_recv_result_active, []}},
+ {options, [{active, true} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{active, true} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
%%--------------------------------------------------------------------
tls_upgrade_with_timeout() ->
[{doc,"Test ssl_accept/3"}].
@@ -5551,11 +5601,7 @@ tls13_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- ssl_test_lib:check_result(Server,
- {error,
- {tls_alert,
- {certificate_required,
- "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:check_server_alert(Server, certificate_required),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -5589,11 +5635,7 @@ tls13_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, ClientOpts}]),
- ssl_test_lib:check_result(Server,
- {error,
- {tls_alert,
- {certificate_required,
- "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:check_server_alert(Server, certificate_required),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -5745,11 +5787,7 @@ tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- ssl_test_lib:check_result(Server,
- {error,
- {tls_alert,
- {certificate_required,
- "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:check_server_alert(Server, certificate_required),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -5785,11 +5823,7 @@ tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, ClientOpts}]),
- ssl_test_lib:check_result(Server,
- {error,
- {tls_alert,
- {certificate_required,
- "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:check_server_alert(Server, certificate_required),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -5945,13 +5979,7 @@ tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client(Config) ->
Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- ssl_test_lib:check_result(
- Server,
- {error,
- {tls_alert,
- {insufficient_security,
- "received SERVER ALERT: Fatal - Insufficient Security - "
- "\"No suitable signature algorithm\""}}}),
+ ssl_test_lib:check_server_alert(Server, insufficient_security),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -5984,13 +6012,7 @@ tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, ClientOpts}]),
- ssl_test_lib:check_result(
- Server,
- {error,
- {tls_alert,
- {insufficient_security,
- "received SERVER ALERT: Fatal - Insufficient Security - "
- "\"No suitable signature algorithm\""}}}),
+ ssl_test_lib:check_server_alert(Server, insufficient_security),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -6024,12 +6046,7 @@ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client(Config) -
Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- ssl_test_lib:check_result(
- Server,
- {error,
- {tls_alert,
- {certificate_required,
- "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:check_server_alert(Server, certificate_required),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -6068,12 +6085,7 @@ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, ClientOpts}]),
- ssl_test_lib:check_result(
- Server,
- {error,
- {tls_alert,
- {certificate_required,
- "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:check_server_alert(Server, certificate_required),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -6101,6 +6113,132 @@ tls13_connection_information(Config) ->
ssl_test_lib:close_port(Client).
+tls13_ssl_server_with_alpn_ssl_client() ->
+ [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client"}].
+
+tls13_ssl_server_with_alpn_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_ssl_server_with_alpn_ssl_client_empty_alpn() ->
+ [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with empty ALPN"}].
+
+tls13_ssl_server_with_alpn_ssl_client_empty_alpn(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_advertised_protocols, []}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_server_alert(Server, no_application_protocol),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_ssl_server_with_alpn_ssl_client_bad_alpn() ->
+ [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with bad ALPN"}].
+
+tls13_ssl_server_with_alpn_ssl_client_bad_alpn(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_advertised_protocols, [<<1,2,3,4>>]}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_server_alert(Server, no_application_protocol),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+tls13_ssl_server_with_alpn_ssl_client_alpn() ->
+ [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with correct ALPN"}].
+
+tls13_ssl_server_with_alpn_ssl_client_alpn(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_advertised_protocols, [<<1,2,3,4>>, <<5,6>>]}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 55dee9a48f..4de4a35e59 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -40,6 +40,7 @@
%%--------------------------------------------------------------------
all() ->
[
+ {group, 'tlsv1.3'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
@@ -50,6 +51,7 @@ all() ->
groups() ->
[
+ {'tlsv1.3', [], all_protocol_groups()},
{'tlsv1.2', [], all_protocol_groups()},
{'tlsv1.1', [], all_protocol_groups()},
{'tlsv1', [], all_protocol_groups()},
@@ -89,7 +91,8 @@ tests() ->
critical_extension_verify_server,
critical_extension_verify_none,
customize_hostname_check,
- incomplete_chain
+ incomplete_chain,
+ long_chain
].
error_handling_tests()->
@@ -300,7 +303,13 @@ server_require_peer_cert_fail(Config) when is_list(Config) ->
{from, self()},
{options, [{active, Active} | BadClientOpts]}]),
- ssl_test_lib:check_server_alert(Server, Client, handshake_failure).
+ Version = proplists:get_value(version,Config),
+ case Version of
+ 'tlsv1.3' ->
+ ssl_test_lib:check_server_alert(Server, Client, certificate_required);
+ _ ->
+ ssl_test_lib:check_server_alert(Server, Client, handshake_failure)
+ end.
%%--------------------------------------------------------------------
server_require_peer_cert_empty_ok() ->
@@ -853,6 +862,7 @@ invalid_signature_server(Config) when is_list(Config) ->
{from, self()},
{options, [{verify, verify_peer} | ClientOpts]}]),
ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
+
%%--------------------------------------------------------------------
invalid_signature_client() ->
@@ -1157,6 +1167,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/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 3b161a0c8a..32fd917937 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -159,6 +159,7 @@ connect(ListenSocket, Node, N, _, Timeout, SslOpts, [_|_] =ContOpts) ->
case ssl:handshake(AcceptSocket, SslOpts, Timeout) of
{ok, Socket0, Ext} ->
+ [_|_] = maps:get(sni, Ext),
ct:log("Ext ~p:~n", [Ext]),
ct:log("~p:~p~nssl:handshake_continue(~p,~p,~p)~n", [?MODULE,?LINE, Socket0, ContOpts,Timeout]),
case ssl:handshake_continue(Socket0, ContOpts, Timeout) of
@@ -427,37 +428,56 @@ check_result(Pid, Msg) ->
{got, Unexpected}},
ct:fail(Reason)
end.
+
check_server_alert(Pid, Alert) ->
receive
- {Pid, {error, {tls_alert, {Alert, _}}}} ->
+ {Pid, {error, {tls_alert, {Alert, STxt}}}} ->
+ check_server_txt(STxt),
+ ok;
+ {Pid, {error, closed}} ->
ok
end.
check_server_alert(Server, Client, Alert) ->
receive
- {Server, {error, {tls_alert, {Alert, _}}}} ->
- receive
- {Client, {error, {tls_alert, {Alert, _}}}} ->
- ok;
- {Client, {error, closed}} ->
- ok
- end
+ {Server, {error, {tls_alert, {Alert, STxt}}}} ->
+ check_server_txt(STxt),
+ check_client_alert(Client, Alert)
end.
check_client_alert(Pid, Alert) ->
receive
- {Pid, {error, {tls_alert, {Alert, _}}}} ->
+ {Pid, {error, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ ok;
+ {Pid, {ssl_error, _, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ ok;
+ {Pid, {error, closed}} ->
ok
end.
check_client_alert(Server, Client, Alert) ->
receive
- {Client, {error, {tls_alert, {Alert, _}}}} ->
- receive
- {Server, {error, {tls_alert, {Alert, _}}}} ->
- ok;
- {Server, {error, closed}} ->
- ok
- end
+ {Client, {error, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ check_server_alert(Server, Alert);
+ {Client, {ssl_error, _, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ ok;
+ {Client, {error, closed}} ->
+ ok
end.
+check_server_txt("TLS server" ++ _) ->
+ ok;
+check_server_txt("DTLS server" ++ _) ->
+ ok;
+check_server_txt(Txt) ->
+ ct:fail({expected_server, {got, Txt}}).
+check_client_txt("TLS client" ++ _) ->
+ ok;
+check_client_txt("DTLS client" ++ _) ->
+ ok;
+check_client_txt(Txt) ->
+ ct:fail({expected_server, {got, Txt}}).
wait_for_result(Server, ServerMsg, Client, ClientMsg) ->
receive
@@ -1084,7 +1104,15 @@ run_client_error(Opts) ->
Options = proplists:get_value(options, Opts),
ct:log("~p:~p~nssl:connect(~p, ~p, ~p)~n", [?MODULE,?LINE, Host, Port, Options]),
Error = Transport:connect(Host, Port, Options),
- Pid ! {self(), Error}.
+ case Error of
+ {error, _} ->
+ Pid ! {self(), Error};
+ {ok, _Socket} ->
+ receive
+ {ssl_error, _, {tls_alert, _}} = SslError ->
+ Pid ! {self(), SslError}
+ end
+ end.
accepters(N) ->
accepters([], N).
@@ -1623,6 +1651,8 @@ is_tls_version('dtlsv1.2') ->
true;
is_tls_version('dtlsv1') ->
true;
+is_tls_version('tlsv1.3') ->
+ true;
is_tls_version('tlsv1.2') ->
true;
is_tls_version('tlsv1.1') ->
@@ -2149,7 +2179,8 @@ clean_env() ->
application:unset_env(ssl, session_cache_server_max),
application:unset_env(ssl, ssl_pem_cache_clean),
application:unset_env(ssl, bypass_pem_cache),
- application:unset_env(ssl, alert_timeout).
+ application:unset_env(ssl, alert_timeout),
+ application:unset_env(ssl, internal_active_n).
clean_start() ->
ssl:stop(),
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index cbc32cd5a8..4e387fa403 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 9.3.1
+SSL_VSN = 9.3.2