aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src/ssl.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src/ssl.erl')
-rw-r--r--lib/ssl/src/ssl.erl1014
1 files changed, 815 insertions, 199 deletions
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index fb4448e180..7c1d0a3829 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,49 +23,356 @@
%%% Purpose : Main API module for SSL see also tls.erl and dtls.erl
-module(ssl).
--include("ssl_internal.hrl").
+
-include_lib("public_key/include/public_key.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_api.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_handshake.hrl").
+-include("ssl_srp.hrl").
+
%% Application handling
-export([start/0, start/1, stop/0, clear_pem_cache/0]).
%% Socket handling
-export([connect/3, connect/2, connect/4,
listen/2, transport_accept/1, transport_accept/2,
- ssl_accept/1, ssl_accept/2, ssl_accept/3,
+ handshake/1, handshake/2, handshake/3, handshake_continue/2,
+ handshake_continue/3, handshake_cancel/1,
+ ssl_accept/1, ssl_accept/2, ssl_accept/3,
controlling_process/2, peername/1, peercert/1, sockname/1,
close/1, close/2, shutdown/2, recv/2, recv/3, send/2,
getopts/2, setopts/2, getstat/1, getstat/2
]).
-%% SSL/TLS protocol handling
+%% SSL/TLS protocol handling
-export([cipher_suites/0, cipher_suites/1, cipher_suites/2, filter_cipher_suites/2,
prepend_cipher_suites/2, append_cipher_suites/2,
eccs/0, eccs/1, versions/0,
format_error/1, renegotiate/1, prf/5, negotiated_protocol/1,
connection_information/1, connection_information/2]).
%% Misc
--export([handle_options/2, tls_version/1]).
+-export([handle_options/2, tls_version/1, new_ssl_options/3, suite_to_str/1]).
+
+-deprecated({ssl_accept, 1, eventually}).
+-deprecated({ssl_accept, 2, eventually}).
+-deprecated({ssl_accept, 3, eventually}).
+
+-export_type([socket/0,
+ sslsocket/0,
+ socket_option/0,
+ active_msgs/0,
+ host/0,
+ tls_option/0,
+ tls_client_option/0,
+ tls_server_option/0,
+ erl_cipher_suite/0,
+ old_cipher_suite/0,
+ ciphers/0,
+ cipher/0,
+ hash/0,
+ kex_algo/0,
+ prf_random/0,
+ cipher_filters/0,
+ sign_algo/0,
+ protocol_version/0,
+ protocol_extensions/0,
+ session_id/0,
+ error_alert/0,
+ srp_param_type/0]).
+
+%% -------------------------------------------------------------------------------------------------------
+
+-type socket() :: gen_tcp:socket(). % exported
+-type socket_option() :: gen_tcp:connect_option() | gen_tcp:listen_option() | gen_udp:option(). % exported
+-type sslsocket() :: any(). % exported
+-type tls_option() :: tls_client_option() | tls_server_option(). % exported
+-type tls_client_option() :: client_option() | common_option() | socket_option() | transport_option(). % exported
+-type tls_server_option() :: server_option() | common_option() | socket_option() | transport_option(). % exported
+-type active_msgs() :: {ssl, sslsocket(), Data::binary() | list()} | {ssl_closed, sslsocket()} |
+ {ssl_error, sslsocket(), Reason::any()} | {ssl_passive, sslsocket()}. % exported
+-type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(),
+ ClosedTag::atom(), ErrTag::atom()}} |
+ {cb_info, {CallbackModule::atom(), DataTag::atom(),
+ ClosedTag::atom(), ErrTag::atom(), PassiveTag::atom()}}.
+-type host() :: hostname() | ip_address(). % exported
+-type hostname() :: string().
+-type ip_address() :: inet:ip_address().
+-type session_id() :: binary().
+-type protocol_version() :: tls_version() | dtls_version().
+-type tls_version() :: tlsv1 | 'tlsv1.1' | 'tlsv1.2' | 'tlsv1.3' | legacy_version().
+-type dtls_version() :: 'dtlsv1' | 'dtlsv1.2'.
+-type legacy_version() :: sslv3.
+-type verify_type() :: verify_none | verify_peer.
+-type cipher() :: aes_128_cbc |
+ aes_256_cbc |
+ aes_128_gcm |
+ aes_256_gcm |
+ chacha20_poly1305 |
+ legacy_cipher(). % exported
+-type legacy_cipher() :: rc4_128 |
+ des_cbc |
+ '3des_ede_cbc'.
+
+-type hash() :: sha |
+ sha2() |
+ legacy_hash(). % exported
+
+-type sha2() :: sha224 |
+ sha256 |
+ sha384 |
+ sha512.
+
+-type legacy_hash() :: md5.
+
+-type sign_algo() :: rsa | dsa | ecdsa.
+-type kex_algo() :: rsa |
+ dhe_rsa | dhe_dss |
+ ecdhe_ecdsa | ecdh_ecdsa | ecdh_rsa |
+ srp_rsa| srp_dss |
+ psk | dhe_psk | rsa_psk |
+ dh_anon | ecdh_anon | srp_anon.
+
+-type erl_cipher_suite() :: #{key_exchange := kex_algo(),
+ cipher := cipher(),
+ mac := hash() | aead,
+ prf := hash() | default_prf %% Old cipher suites, version dependent
+ }.
+
+-type old_cipher_suite() :: {kex_algo(), cipher(), hash()} % Pre TLS 1.2
+ %% TLS 1.2, internally PRE TLS 1.2 will use default_prf
+ | {kex_algo(), cipher(), hash() | aead, hash()}.
+
+-type named_curve() :: sect571r1 |
+ sect571k1 |
+ secp521r1 |
+ brainpoolP512r1 |
+ sect409k1 |
+ sect409r1 |
+ brainpoolP384r1 |
+ secp384r1 |
+ sect283k1 |
+ sect283r1 |
+ brainpoolP256r1 |
+ secp256k1 |
+ secp256r1 |
+ sect239k1 |
+ sect233k1 |
+ sect233r1 |
+ secp224k1 |
+ secp224r1 |
+ sect193r1 |
+ sect193r2 |
+ secp192k1 |
+ secp192r1 |
+ sect163k1 |
+ sect163r1 |
+ sect163r2 |
+ secp160k1 |
+ secp160r1 |
+ secp160r2.
+
+-type srp_param_type() :: srp_1024 |
+ srp_1536 |
+ srp_2048 |
+ srp_3072 |
+ srp_4096 |
+ srp_6144 |
+ srp_8192. % exported
+
+-type error_alert() :: {tls_alert, {tls_alert(), Description::string()}}. % exported
+
+-type tls_alert() :: close_notify |
+ unexpected_message |
+ bad_record_mac |
+ record_overflow |
+ handshake_failure |
+ bad_certificate |
+ unsupported_certificate |
+ certificate_revoked |
+ certificate_expired |
+ certificate_unknown |
+ illegal_parameter |
+ unknown_ca |
+ access_denied |
+ decode_error |
+ decrypt_error |
+ export_restriction|
+ protocol_version |
+ insufficient_security |
+ internal_error |
+ inappropriate_fallback |
+ user_canceled |
+ no_renegotiation |
+ unsupported_extension |
+ certificate_unobtainable |
+ unrecognized_name |
+ bad_certificate_status_response |
+ bad_certificate_hash_value |
+ unknown_psk_identity |
+ no_application_protocol.
+
+%% -------------------------------------------------------------------------------------------------------
+-type common_option() :: {protocol, protocol()} |
+ {handshake, handshake_completion()} |
+ {cert, cert()} |
+ {certfile, cert_pem()} |
+ {key, key()} |
+ {keyfile, key_pem()} |
+ {password, key_password()} |
+ {ciphers, cipher_suites()} |
+ {secure_renegotiate, secure_renegotiation()} |
+ {depth, allowed_cert_chain_length()} |
+ {verify_fun, custom_verify()} |
+ {crl_check, crl_check()} |
+ {crl_cache, crl_cache_opts()} |
+ {max_handshake_size, handshake_size()} |
+ {partial_chain, root_fun()} |
+ {versions, protocol_versions()} |
+ {user_lookup_fun, custom_user_lookup()} |
+ {log_alert, log_alert()} |
+ {hibernate_after, hibernate_after()} |
+ {padding_check, padding_check()} |
+ {beast_mitigation, beast_mitigation()} |
+ {ssl_imp, ssl_imp()}.
+
+-type protocol() :: tls | dtls.
+-type handshake_completion() :: hello | full.
+-type cert() :: public_key:der_encoded().
+-type cert_pem() :: file:filename().
+-type key() :: {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo',
+ public_key:der_encoded()} |
+ #{algorithm := rsa | dss | ecdsa,
+ engine := crypto:engine_ref(),
+ key_id := crypto:key_id(),
+ password => crypto:password()}. % exported
+-type key_pem() :: file:filename().
+-type key_password() :: string().
+-type cipher_suites() :: ciphers().
+-type ciphers() :: [erl_cipher_suite()] |
+ string(). % (according to old API) exported
+-type cipher_filters() :: list({key_exchange | cipher | mac | prf,
+ algo_filter()}). % exported
+-type algo_filter() :: fun((kex_algo()|cipher()|hash()|aead|default_prf) -> true | false).
+-type secure_renegotiation() :: boolean().
+-type allowed_cert_chain_length() :: integer().
+-type custom_verify() :: {Verifyfun :: fun(), InitialUserState :: term()}.
+-type crl_check() :: boolean() | peer | best_effort.
+-type crl_cache_opts() :: [term()].
+-type handshake_size() :: integer().
+-type hibernate_after() :: timeout().
+-type root_fun() :: fun().
+-type protocol_versions() :: [protocol_version()].
+-type signature_algs() :: [{hash(), sign_algo()}].
+-type custom_user_lookup() :: {Lookupfun :: fun(), UserState :: term()}.
+-type padding_check() :: boolean().
+-type beast_mitigation() :: one_n_minus_one | zero_n | disabled.
+-type srp_identity() :: {Username :: string(), Password :: string()}.
+-type psk_identity() :: string().
+-type log_alert() :: boolean().
+
+%% -------------------------------------------------------------------------------------------------------
+
+-type client_option() :: {verify, client_verify_type()} |
+ {reuse_session, client_reuse_session()} |
+ {reuse_sessions, client_reuse_sessions()} |
+ {cacerts, client_cacerts()} |
+ {cacertfile, client_cafile()} |
+ {alpn_advertised_protocols, client_alpn()} |
+ {client_preferred_next_protocols, client_preferred_next_protocols()} |
+ {psk_identity, client_psk_identity()} |
+ {srp_identity, client_srp_identity()} |
+ {server_name_indication, sni()} |
+ {customize_hostname_check, customize_hostname_check()} |
+ {signature_algs, client_signature_algs()} |
+ {fallback, fallback()}.
+
+-type client_verify_type() :: verify_type().
+-type client_reuse_session() :: session_id().
+-type client_reuse_sessions() :: boolean() | save.
+-type client_cacerts() :: [public_key:der_encoded()].
+-type client_cafile() :: file:filename().
+-type app_level_protocol() :: binary().
+-type client_alpn() :: [app_level_protocol()].
+-type client_preferred_next_protocols() :: {Precedence :: server | client,
+ ClientPrefs :: [app_level_protocol()]} |
+ {Precedence :: server | client,
+ ClientPrefs :: [app_level_protocol()],
+ Default::app_level_protocol()}.
+-type client_psk_identity() :: psk_identity().
+-type client_srp_identity() :: srp_identity().
+-type customize_hostname_check() :: list().
+-type sni() :: HostName :: hostname() | disable.
+-type client_signature_algs() :: signature_algs().
+-type fallback() :: boolean().
+-type ssl_imp() :: new | old.
+
+%% -------------------------------------------------------------------------------------------------------
+-type server_option() :: {cacerts, server_cacerts()} |
+ {cacertfile, server_cafile()} |
+ {dh, dh_der()} |
+ {dhfile, dh_file()} |
+ {verify, server_verify_type()} |
+ {fail_if_no_peer_cert, fail_if_no_peer_cert()} |
+ {reuse_sessions, server_reuse_sessions()} |
+ {reuse_session, server_reuse_session()} |
+ {alpn_preferred_protocols, server_alpn()} |
+ {next_protocols_advertised, server_next_protocol()} |
+ {psk_identity, server_psk_identity()} |
+ {honor_cipher_order, boolean()} |
+ {sni_hosts, sni_hosts()} |
+ {sni_fun, sni_fun()} |
+ {honor_cipher_order, honor_cipher_order()} |
+ {honor_ecc_order, honor_ecc_order()} |
+ {client_renegotiation, client_renegotiation()}|
+ {signature_algs, server_signature_algs()}.
+
+-type server_cacerts() :: [public_key:der_encoded()].
+-type server_cafile() :: file:filename().
+-type server_alpn() :: [app_level_protocol()].
+-type server_next_protocol() :: [app_level_protocol()].
+-type server_psk_identity() :: psk_identity().
+-type dh_der() :: binary().
+-type dh_file() :: file:filename().
+-type server_verify_type() :: verify_type().
+-type fail_if_no_peer_cert() :: boolean().
+-type server_signature_algs() :: signature_algs().
+-type server_reuse_session() :: fun().
+-type server_reuse_sessions() :: boolean().
+-type sni_hosts() :: [{hostname(), [server_option() | common_option()]}].
+-type sni_fun() :: fun().
+-type honor_cipher_order() :: boolean().
+-type honor_ecc_order() :: boolean().
+-type client_renegotiation() :: boolean().
+%% -------------------------------------------------------------------------------------------------------
+-type prf_random() :: client_random | server_random. % exported
+-type protocol_extensions() :: #{renegotiation_info => binary(),
+ signature_algs => signature_algs(),
+ alpn => app_level_protocol(),
+ srp => binary(),
+ next_protocol => app_level_protocol(),
+ ec_point_formats => [0..2],
+ elliptic_curves => [public_key:oid()],
+ sni => hostname()}. % exported
+%% -------------------------------------------------------------------------------------------------------
--include("ssl_api.hrl").
--include("ssl_internal.hrl").
--include("ssl_record.hrl").
--include("ssl_cipher.hrl").
--include("ssl_handshake.hrl").
--include("ssl_srp.hrl").
-
--include_lib("public_key/include/public_key.hrl").
+%%%--------------------------------------------------------------------
+%%% API
+%%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
--spec start() -> ok | {error, reason()}.
--spec start(permanent | transient | temporary) -> ok | {error, reason()}.
%%
%% Description: Utility function that starts the ssl and applications
%% that it depends on.
%% see application(3)
%%--------------------------------------------------------------------
+-spec start() -> ok | {error, reason()}.
start() ->
start(temporary).
+-spec start(permanent | transient | temporary) -> ok | {error, reason()}.
start(Type) ->
case application:ensure_all_started(ssl, Type) of
{ok, _} ->
@@ -82,24 +389,36 @@ stop() ->
application:stop(ssl).
%%--------------------------------------------------------------------
--spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
- {error, reason()}.
--spec connect(host() | port(), [connect_option()] | inet:port_number(),
- timeout() | list()) ->
- {ok, #sslsocket{}} | {error, reason()}.
--spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
%%
%% Description: Connect to an ssl server.
%%--------------------------------------------------------------------
+-spec connect(TCPSocket, TLSOptions) ->
+ {ok, sslsocket()} |
+ {error, reason()} |
+ {option_not_a_key_value_tuple, any()} when
+ TCPSocket :: socket(),
+ TLSOptions :: [tls_client_option()].
+
connect(Socket, SslOptions) when is_port(Socket) ->
connect(Socket, SslOptions, infinity).
+-spec connect(TCPSocket, TLSOptions, Timeout) ->
+ {ok, sslsocket()} | {error, reason()} when
+ TCPSocket :: socket(),
+ TLSOptions :: [tls_client_option()],
+ Timeout :: timeout();
+ (Host, Port, TLSOptions) ->
+ {ok, sslsocket()} |
+ {ok, sslsocket(),Ext :: protocol_extensions()} |
+ {error, reason()} |
+ {option_not_a_key_value_tuple, any()} when
+ Host :: host(),
+ Port :: inet:port_number(),
+ TLSOptions :: [tls_client_option()].
connect(Socket, SslOptions0, Timeout) when is_port(Socket),
- (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0,
- {gen_tcp, tcp, tcp_closed, tcp_error}),
+ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+ CbInfo = handle_option(cb_info, SslOptions0, default_cb_info(tls)),
+ Transport = element(1, CbInfo),
EmulatedOptions = tls_socket:emulated_options(),
{ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
try handle_options(SslOptions0 ++ SocketValues, client) of
@@ -112,6 +431,16 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket),
connect(Host, Port, Options) ->
connect(Host, Port, Options, infinity).
+-spec connect(Host, Port, TLSOptions, Timeout) ->
+ {ok, sslsocket()} |
+ {ok, sslsocket(),Ext :: protocol_extensions()} |
+ {error, reason()} |
+ {option_not_a_key_value_tuple, any()} when
+ Host :: host(),
+ Port :: inet:port_number(),
+ TLSOptions :: [tls_client_option()],
+ Timeout :: timeout().
+
connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
try
{ok, Config} = handle_options(Options, client, Host),
@@ -127,7 +456,10 @@ connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout
end.
%%--------------------------------------------------------------------
--spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
+-spec listen(Port, Options) -> {ok, ListenSocket} | {error, reason()} when
+ Port::inet:port_number(),
+ Options::[tls_server_option()],
+ ListenSocket :: sslsocket().
%%
%% Description: Creates an ssl listen socket.
@@ -143,16 +475,23 @@ listen(Port, Options0) ->
Error
end.
%%--------------------------------------------------------------------
--spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}} |
- {error, reason()}.
--spec transport_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} |
- {error, reason()}.
%%
%% Description: Performs transport accept on an ssl listen socket
%%--------------------------------------------------------------------
+-spec transport_accept(ListenSocket) -> {ok, SslSocket} |
+ {error, reason()} when
+ ListenSocket :: sslsocket(),
+ SslSocket :: sslsocket().
+
transport_accept(ListenSocket) ->
transport_accept(ListenSocket, infinity).
+-spec transport_accept(ListenSocket, Timeout) -> {ok, SslSocket} |
+ {error, reason()} when
+ ListenSocket :: sslsocket(),
+ Timeout :: timeout(),
+ SslSocket :: sslsocket().
+
transport_accept(#sslsocket{pid = {ListenSocket,
#config{connection_cb = ConnectionCb} = Config}}, Timeout)
when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
@@ -164,29 +503,101 @@ transport_accept(#sslsocket{pid = {ListenSocket,
end.
%%--------------------------------------------------------------------
--spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}.
--spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option()
- | transport_option()]) ->
- ok | {ok, #sslsocket{}} | {error, reason()}.
-
--spec ssl_accept(#sslsocket{} | port(), [ssl_option()] | [ssl_option()| transport_option()], timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on an ssl listen socket. e.i. performs
%% ssl handshake.
%%--------------------------------------------------------------------
+-spec ssl_accept(SslSocket) ->
+ ok |
+ {error, Reason} when
+ SslSocket :: sslsocket(),
+ Reason :: closed | timeout | error_alert().
+
ssl_accept(ListenSocket) ->
- ssl_accept(ListenSocket, infinity).
+ ssl_accept(ListenSocket, [], infinity).
+
+-spec ssl_accept(Socket, TimeoutOrOptions) ->
+ ok |
+ {ok, sslsocket()} | {error, Reason} when
+ Socket :: sslsocket() | socket(),
+ TimeoutOrOptions :: timeout() | [tls_server_option()],
+ Reason :: timeout | closed | {options, any()} | error_alert().
+
+ssl_accept(Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+ ssl_accept(Socket, [], Timeout);
+ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
+ ssl_accept(ListenSocket, SslOptions, infinity);
+ssl_accept(Socket, Timeout) ->
+ ssl_accept(Socket, [], Timeout).
+
+-spec ssl_accept(Socket, Options, Timeout) ->
+ ok | {ok, sslsocket()} | {error, Reason} when
+ Socket :: sslsocket() | socket(),
+ Options :: [tls_server_option()],
+ Timeout :: timeout(),
+ Reason :: timeout | closed | {options, any()} | error_alert().
+
+ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
+ handshake(Socket, SslOptions, Timeout);
+ssl_accept(Socket, SslOptions, Timeout) ->
+ case handshake(Socket, SslOptions, Timeout) of
+ {ok, _} ->
+ ok;
+ Error ->
+ Error
+ end.
+%%--------------------------------------------------------------------
+%%
+%% Description: Performs accept on an ssl listen socket. e.i. performs
+%% ssl handshake.
+%%--------------------------------------------------------------------
-ssl_accept(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+%% Performs the SSL/TLS/DTLS server-side handshake.
+
+-spec handshake(HsSocket) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason} when
+ HsSocket :: sslsocket(),
+ SslSocket :: sslsocket(),
+ Ext :: protocol_extensions(),
+ Reason :: closed | timeout | error_alert().
+
+handshake(ListenSocket) ->
+ handshake(ListenSocket, infinity).
+
+-spec handshake(HsSocket, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason} when
+ HsSocket :: sslsocket(),
+ Timeout :: timeout(),
+ SslSocket :: sslsocket(),
+ Ext :: protocol_extensions(),
+ Reason :: closed | timeout | error_alert();
+ (Socket, Options) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason} when
+ Socket :: socket() | sslsocket(),
+ SslSocket :: sslsocket(),
+ Options :: [server_option()],
+ Ext :: protocol_extensions(),
+ Reason :: closed | timeout | error_alert().
+
+handshake(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or
+ (Timeout == infinity) ->
ssl_connection:handshake(Socket, Timeout);
-ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
- ssl_accept(ListenSocket, SslOptions, infinity).
-
-ssl_accept(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
- ssl_accept(Socket, Timeout);
-ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
+handshake(ListenSocket, SslOptions) when is_port(ListenSocket) ->
+ handshake(ListenSocket, SslOptions, infinity).
+
+-spec handshake(Socket, Options, Timeout) ->
+ {ok, SslSocket} |
+ {ok, SslSocket, Ext} |
+ {error, Reason} when
+ Socket :: socket() | sslsocket(),
+ SslSocket :: sslsocket(),
+ Options :: [server_option()],
+ Timeout :: timeout(),
+ Ext :: protocol_extensions(),
+ Reason :: closed | timeout | {options, any()} | error_alert().
+
+handshake(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or
+ (Timeout == infinity)->
+ handshake(Socket, Timeout);
+handshake(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
try
{ok, EmOpts, _} = tls_socket:get_all_opts(Tracker),
@@ -195,19 +606,19 @@ ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
catch
Error = {error, _Reason} -> Error
end;
-ssl_accept(#sslsocket{pid = Pid, fd = {_, _, _}} = Socket, SslOpts, Timeout) when
+handshake(#sslsocket{pid = [Pid|_], fd = {_, _, _}} = Socket, SslOpts, Timeout) when
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
try
- {ok, EmOpts, _} = dtls_udp_listener:get_all_opts(Pid),
+ {ok, EmOpts, _} = dtls_packet_demux:get_all_opts(Pid),
ssl_connection:handshake(Socket, {SslOpts,
tls_socket:emulated_socket_options(EmOpts, #socket_options{})}, Timeout)
catch
Error = {error, _Reason} -> Error
end;
-ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket),
- (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- {Transport,_,_,_} =
- proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
+handshake(Socket, SslOptions, Timeout) when is_port(Socket),
+ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+ CbInfo = handle_option(cb_info, SslOptions, default_cb_info(tls)),
+ Transport = element(1, CbInfo),
EmulatedOptions = tls_socket:emulated_options(),
{ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
ConnetionCb = connection_cb(SslOptions),
@@ -215,85 +626,148 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket),
{ok, #config{transport_info = CbInfo, ssl = SslOpts, emulated = EmOpts}} ->
ok = tls_socket:setopts(Transport, Socket, tls_socket:internal_inet_values()),
{ok, Port} = tls_socket:port(Transport, Socket),
- ssl_connection:ssl_accept(ConnetionCb, Port, Socket,
- {SslOpts,
- tls_socket:emulated_socket_options(EmOpts, #socket_options{}), undefined},
- self(), CbInfo, Timeout)
+ ssl_connection:handshake(ConnetionCb, Port, Socket,
+ {SslOpts,
+ tls_socket:emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ self(), CbInfo, Timeout)
catch
Error = {error, _Reason} -> Error
end.
+
+
%%--------------------------------------------------------------------
--spec close(#sslsocket{}) -> term().
+-spec handshake_continue(HsSocket, Options) ->
+ {ok, SslSocket} | {error, Reason} when
+ HsSocket :: sslsocket(),
+ Options :: [tls_client_option() | tls_server_option()],
+ SslSocket :: sslsocket(),
+ Reason :: closed | timeout | error_alert().
+%%
+%%
+%% Description: Continues the handshke possible with newly supplied options.
+%%--------------------------------------------------------------------
+handshake_continue(Socket, SSLOptions) ->
+ handshake_continue(Socket, SSLOptions, infinity).
+%%--------------------------------------------------------------------
+-spec handshake_continue(HsSocket, Options, Timeout) ->
+ {ok, SslSocket} | {error, Reason} when
+ HsSocket :: sslsocket(),
+ Options :: [tls_client_option() | tls_server_option()],
+ Timeout :: timeout(),
+ SslSocket :: sslsocket(),
+ Reason :: closed | timeout | error_alert().
+%%
+%%
+%% Description: Continues the handshke possible with newly supplied options.
+%%--------------------------------------------------------------------
+handshake_continue(Socket, SSLOptions, Timeout) ->
+ ssl_connection:handshake_continue(Socket, SSLOptions, Timeout).
+%%--------------------------------------------------------------------
+-spec handshake_cancel(#sslsocket{}) -> any().
+%%
+%% Description: Cancels the handshakes sending a close alert.
+%%--------------------------------------------------------------------
+handshake_cancel(Socket) ->
+ ssl_connection:handshake_cancel(Socket).
+
+%%--------------------------------------------------------------------
+-spec close(SslSocket) -> ok | {error, Reason} when
+ SslSocket :: sslsocket(),
+ Reason :: any().
%%
%% Description: Close an ssl connection
%%--------------------------------------------------------------------
-close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+close(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
ssl_connection:close(Pid, {close, ?DEFAULT_TIMEOUT});
-close(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
- dtls_udp_listener:close(Pid);
-close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}) ->
+close(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
+ dtls_packet_demux:close(Pid);
+close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_,_,_,_}}}}) ->
Transport:close(ListenSocket).
%%--------------------------------------------------------------------
--spec close(#sslsocket{}, timeout() | {pid(), integer()}) -> term().
+-spec close(SslSocket, How) -> ok | {ok, port()} | {error,Reason} when
+ SslSocket :: sslsocket(),
+ How :: timeout() | {NewController::pid(), timeout()},
+ Reason :: any().
%%
%% Description: Close an ssl connection
%%--------------------------------------------------------------------
-close(#sslsocket{pid = TLSPid},
+close(#sslsocket{pid = [TLSPid|_]},
{Pid, Timeout} = DownGrade) when is_pid(TLSPid),
is_pid(Pid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
ssl_connection:close(TLSPid, {close, DownGrade});
-close(#sslsocket{pid = TLSPid}, Timeout) when is_pid(TLSPid),
+close(#sslsocket{pid = [TLSPid|_]}, Timeout) when is_pid(TLSPid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
ssl_connection:close(TLSPid, {close, Timeout});
-close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}, _) ->
+close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_,_,_,_}}}}, _) ->
Transport:close(ListenSocket).
%%--------------------------------------------------------------------
--spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}.
+-spec send(SslSocket, Data) -> ok | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Data :: iodata().
%%
%% Description: Sends data over the ssl connection
%%--------------------------------------------------------------------
-send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
+send(#sslsocket{pid = [Pid]}, Data) when is_pid(Pid) ->
ssl_connection:send(Pid, Data);
-send(#sslsocket{pid = {_, #config{transport_info={gen_udp, _, _, _}}}}, _) ->
+send(#sslsocket{pid = [_, Pid]}, Data) when is_pid(Pid) ->
+ tls_sender:send_data(Pid, erlang:iolist_to_iovec(Data));
+send(#sslsocket{pid = {_, #config{transport_info={_, udp, _, _}}}}, _) ->
{error,enotconn}; %% Emulate connection behaviour
-send(#sslsocket{pid = {udp,_}}, _) ->
- {error,enotconn};
-send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _}}}}, Data) ->
+send(#sslsocket{pid = {dtls,_}}, _) ->
+ {error,enotconn}; %% Emulate connection behaviour
+send(#sslsocket{pid = {ListenSocket, #config{transport_info = Info}}}, Data) ->
+ Transport = element(1, Info),
Transport:send(ListenSocket, Data). %% {error,enotconn}
%%--------------------------------------------------------------------
--spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}.
--spec recv(#sslsocket{}, integer(), timeout()) -> {ok, binary()| list()} | {error, reason()}.
%%
%% Description: Receives data when active = false
%%--------------------------------------------------------------------
+-spec recv(SslSocket, Length) -> {ok, Data} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Length :: integer(),
+ Data :: binary() | list() | HttpPacket,
+ HttpPacket :: any().
+
recv(Socket, Length) ->
recv(Socket, Length, infinity).
-recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid),
+
+-spec recv(SslSocket, Length, Timeout) -> {ok, Data} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Length :: integer(),
+ Data :: binary() | list() | HttpPacket,
+ Timeout :: timeout(),
+ HttpPacket :: any().
+
+recv(#sslsocket{pid = [Pid|_]}, Length, Timeout) when is_pid(Pid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
ssl_connection:recv(Pid, Length, Timeout);
-recv(#sslsocket{pid = {udp,_}}, _, _) ->
+recv(#sslsocket{pid = {dtls,_}}, _, _) ->
{error,enotconn};
recv(#sslsocket{pid = {Listen,
- #config{transport_info = {Transport, _, _, _}}}}, _,_) when is_port(Listen)->
+ #config{transport_info = Info}}},_,_) when is_port(Listen)->
+ Transport = element(1, Info),
Transport:recv(Listen, 0). %% {error,enotconn}
%%--------------------------------------------------------------------
--spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
+-spec controlling_process(SslSocket, NewOwner) -> ok | {error, Reason} when
+ SslSocket :: sslsocket(),
+ NewOwner :: pid(),
+ Reason :: any().
%%
%% Description: Changes process that receives the messages when active = true
%% or once.
%%--------------------------------------------------------------------
-controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
+controlling_process(#sslsocket{pid = [Pid|_]}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
ssl_connection:new_user(Pid, NewOwner);
-controlling_process(#sslsocket{pid = {udp, _}},
+controlling_process(#sslsocket{pid = {dtls, _}},
NewOwner) when is_pid(NewOwner) ->
ok; %% Meaningless but let it be allowed to conform with TLS
controlling_process(#sslsocket{pid = {Listen,
- #config{transport_info = {Transport, _, _, _}}}},
+ #config{transport_info = {Transport,_,_,_,_}}}},
NewOwner) when is_port(Listen),
is_pid(NewOwner) ->
%% Meaningless but let it be allowed to conform with normal sockets
@@ -301,11 +775,15 @@ controlling_process(#sslsocket{pid = {Listen,
%%--------------------------------------------------------------------
--spec connection_information(#sslsocket{}) -> {ok, list()} | {error, reason()}.
+-spec connection_information(SslSocket) -> {ok, Result} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Result :: [{OptionName, OptionValue}],
+ OptionName :: atom(),
+ OptionValue :: any().
%%
%% Description: Return SSL information for the connection
%%--------------------------------------------------------------------
-connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+connection_information(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
case ssl_connection:connection_information(Pid, false) of
{ok, Info} ->
{ok, [Item || Item = {_Key, Value} <- Info, Value =/= undefined]};
@@ -314,15 +792,20 @@ connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) ->
end;
connection_information(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn};
-connection_information(#sslsocket{pid = {udp,_}}) ->
+connection_information(#sslsocket{pid = {dtls,_}}) ->
{error,enotconn}.
%%--------------------------------------------------------------------
--spec connection_information(#sslsocket{}, [atom()]) -> {ok, list()} | {error, reason()}.
+-spec connection_information(SslSocket, Items) -> {ok, Result} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Items :: [OptionName],
+ Result :: [{OptionName, OptionValue}],
+ OptionName :: atom(),
+ OptionValue :: any().
%%
%% Description: Return SSL information for the connection
%%--------------------------------------------------------------------
-connection_information(#sslsocket{pid = Pid}, Items) when is_pid(Pid) ->
+connection_information(#sslsocket{pid = [Pid|_]}, Items) when is_pid(Pid) ->
case ssl_connection:connection_information(Pid, include_security_info(Items)) of
{ok, Info} ->
{ok, [Item || Item = {Key, Value} <- Info, lists:member(Key, Items),
@@ -332,73 +815,82 @@ connection_information(#sslsocket{pid = Pid}, Items) when is_pid(Pid) ->
end.
%%--------------------------------------------------------------------
--spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
+-spec peername(SslSocket) -> {ok, {Address, Port}} |
+ {error, reason()} when
+ SslSocket :: sslsocket(),
+ Address :: inet:ip_address(),
+ Port :: inet:port_number().
%%
%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
-peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid)->
+peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket,_}}) when is_pid(Pid)->
dtls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid)->
+peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket,_,_}}) when is_pid(Pid)->
tls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = {udp = Transport, #config{udp_handler = {_Pid, _}}}}) ->
- dtls_socket:peername(Transport, undefined);
-peername(#sslsocket{pid = Pid, fd = {gen_udp= Transport, Socket, _, _}}) when is_pid(Pid) ->
- dtls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}) ->
+peername(#sslsocket{pid = {dtls, #config{dtls_handler = {_Pid,_}}}}) ->
+ dtls_socket:peername(dtls, undefined);
+peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_,_}}}}) ->
tls_socket:peername(Transport, ListenSocket); %% Will return {error, enotconn}
-peername(#sslsocket{pid = {udp,_}}) ->
+peername(#sslsocket{pid = {dtls,_}}) ->
{error,enotconn}.
%%--------------------------------------------------------------------
--spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
+-spec peercert(SslSocket) -> {ok, Cert} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Cert :: binary().
%%
%% Description: Returns the peercert.
%%--------------------------------------------------------------------
-peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+peercert(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
case ssl_connection:peer_certificate(Pid) of
{ok, undefined} ->
{error, no_peercert};
Result ->
Result
end;
-peercert(#sslsocket{pid = {udp, _}}) ->
+peercert(#sslsocket{pid = {dtls, _}}) ->
{error, enotconn};
peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn}.
%%--------------------------------------------------------------------
--spec negotiated_protocol(#sslsocket{}) -> {ok, binary()} | {error, reason()}.
+-spec negotiated_protocol(SslSocket) -> {ok, Protocol} | {error, Reason} when
+ SslSocket :: sslsocket(),
+ Protocol :: binary(),
+ Reason :: protocol_not_negotiated.
%%
%% Description: Returns the protocol that has been negotiated. If no
%% protocol has been negotiated will return {error, protocol_not_negotiated}
%%--------------------------------------------------------------------
-negotiated_protocol(#sslsocket{pid = Pid}) ->
+negotiated_protocol(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
ssl_connection:negotiated_protocol(Pid).
%%--------------------------------------------------------------------
--spec cipher_suites() -> [ssl_cipher:old_erl_cipher_suite()] | [string()].
+-spec cipher_suites() -> [old_cipher_suite()] | [string()].
%%--------------------------------------------------------------------
cipher_suites() ->
cipher_suites(erlang).
%%--------------------------------------------------------------------
--spec cipher_suites(erlang | openssl | all) ->
- [ssl_cipher:old_erl_cipher_suite() | string()].
+-spec cipher_suites(Type) -> [old_cipher_suite() | string()] when
+ Type :: erlang | openssl | all.
+
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
cipher_suites(erlang) ->
- [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(default)];
+ [ssl_cipher_format:erl_suite_definition(Suite) || Suite <- available_suites(default)];
cipher_suites(openssl) ->
- [ssl_cipher:openssl_suite_name(Suite) ||
+ [ssl_cipher_format:openssl_suite_name(Suite) ||
Suite <- available_suites(default)];
cipher_suites(all) ->
- [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(all)].
+ [ssl_cipher_format:erl_suite_definition(Suite) || Suite <- available_suites(all)].
%%--------------------------------------------------------------------
--spec cipher_suites(default | all | anonymous, tls_record:tls_version() | dtls_record:dtls_version() |
- tls_record:tls_atom_version() | dtls_record:dtls_atom_version()) ->
- [ssl_cipher:erl_cipher_suite()].
+-spec cipher_suites(Supported, Version) -> ciphers() when
+ Supported :: default | all | anonymous,
+ Version :: protocol_version().
+
%% Description: Returns all default and all supported cipher suites for a
%% TLS/DTLS version
%%--------------------------------------------------------------------
@@ -411,12 +903,14 @@ cipher_suites(Base, Version) when Version == 'dtlsv1.2';
Version == 'dtlsv1'->
cipher_suites(Base, dtls_record:protocol_version(Version));
cipher_suites(Base, Version) ->
- [ssl_cipher:suite_definition(Suite) || Suite <- supported_suites(Base, Version)].
+ [ssl_cipher_format:suite_definition(Suite) || Suite <- supported_suites(Base, Version)].
%%--------------------------------------------------------------------
--spec filter_cipher_suites([ssl_cipher:erl_cipher_suite()],
- [{key_exchange | cipher | mac | prf, fun()}] | []) ->
- [ssl_cipher:erl_cipher_suite()].
+-spec filter_cipher_suites(Suites, Filters) -> Ciphers when
+ Suites :: ciphers(),
+ Filters :: cipher_filters(),
+ Ciphers :: ciphers().
+
%% Description: Removes cipher suites if any of the filter functions returns false
%% for any part of the cipher suite. This function also calls default filter functions
%% to make sure the cipher suite are supported by crypto.
@@ -433,10 +927,10 @@ filter_cipher_suites(Suites, Filters0) ->
prf_filters => add_filter(proplists:get_value(prf, Filters0), PrfF)},
ssl_cipher:filter_suites(Suites, Filters).
%%--------------------------------------------------------------------
--spec prepend_cipher_suites([ssl_cipher:erl_cipher_suite()] |
- [{key_exchange | cipher | mac | prf, fun()}],
- [ssl_cipher:erl_cipher_suite()]) ->
- [ssl_cipher:erl_cipher_suite()].
+-spec prepend_cipher_suites(Preferred, Suites) -> ciphers() when
+ Preferred :: ciphers() | cipher_filters(),
+ Suites :: ciphers().
+
%% Description: Make <Preferred> suites become the most prefered
%% suites that is put them at the head of the cipher suite list
%% and remove them from <Suites> if present. <Preferred> may be a
@@ -451,10 +945,10 @@ prepend_cipher_suites(Filters, Suites) ->
Preferred = filter_cipher_suites(Suites, Filters),
Preferred ++ (Suites -- Preferred).
%%--------------------------------------------------------------------
--spec append_cipher_suites(Deferred :: [ssl_cipher:erl_cipher_suite()] |
- [{key_exchange | cipher | mac | prf, fun()}],
- [ssl_cipher:erl_cipher_suite()]) ->
- [ssl_cipher:erl_cipher_suite()].
+-spec append_cipher_suites(Deferred, Suites) -> ciphers() when
+ Deferred :: ciphers() | cipher_filters(),
+ Suites :: ciphers().
+
%% Description: Make <Deferred> suites suites become the
%% least prefered suites that is put them at the end of the cipher suite list
%% and removed them from <Suites> if present.
@@ -468,7 +962,9 @@ append_cipher_suites(Filters, Suites) ->
(Suites -- Deferred) ++ Deferred.
%%--------------------------------------------------------------------
--spec eccs() -> tls_v1:curves().
+-spec eccs() -> NamedCurves when
+ NamedCurves :: [named_curve()].
+
%% Description: returns all supported curves across all versions
%%--------------------------------------------------------------------
eccs() ->
@@ -476,18 +972,24 @@ eccs() ->
eccs_filter_supported(Curves).
%%--------------------------------------------------------------------
--spec eccs(tls_record:tls_version() | tls_record:tls_atom_version()) ->
- tls_v1:curves().
+-spec eccs(Version) -> NamedCurves when
+ Version :: protocol_version(),
+ NamedCurves :: [named_curve()].
+
%% Description: returns the curves supported for a given version of
%% ssl/tls.
%%--------------------------------------------------------------------
-eccs({3,0}) ->
+eccs(sslv3) ->
[];
-eccs({3,_}) ->
+eccs('dtlsv1') ->
+ eccs('tlsv1.1');
+eccs('dtlsv1.2') ->
+ eccs('tlsv1.2');
+eccs(Version) when Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1 ->
Curves = tls_v1:ecc_curves(all),
- eccs_filter_supported(Curves);
-eccs(AtomVersion) when is_atom(AtomVersion) ->
- eccs(tls_record:protocol_version(AtomVersion)).
+ eccs_filter_supported(Curves).
eccs_filter_supported(Curves) ->
CryptoCurves = crypto:ec_curves(),
@@ -495,14 +997,16 @@ eccs_filter_supported(Curves) ->
Curves).
%%--------------------------------------------------------------------
--spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
- {ok, [gen_tcp:option()]} | {error, reason()}.
+-spec getopts(SslSocket, OptionNames) ->
+ {ok, [gen_tcp:option()]} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ OptionNames :: [gen_tcp:option_name()].
%%
%% Description: Gets options
%%--------------------------------------------------------------------
-getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
+getopts(#sslsocket{pid = [Pid|_]}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
ssl_connection:get_opts(Pid, OptionTags);
-getopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) ->
+getopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) ->
try dtls_socket:getopts(Transport, ListenSocket, OptionTags) of
{ok, _} = Result ->
Result;
@@ -512,7 +1016,7 @@ getopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = L
_:Error ->
{error, {options, {socket_options, OptionTags, Error}}}
end;
-getopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket,
+getopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_,_}}}} = ListenSocket,
OptionTags) when is_list(OptionTags) ->
try tls_socket:getopts(Transport, ListenSocket, OptionTags) of
{ok, _} = Result ->
@@ -527,11 +1031,32 @@ getopts(#sslsocket{}, OptionTags) ->
{error, {options, {socket_options, OptionTags}}}.
%%--------------------------------------------------------------------
--spec setopts(#sslsocket{}, [gen_tcp:option()]) -> ok | {error, reason()}.
+-spec setopts(SslSocket, Options) -> ok | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Options :: [gen_tcp:option()].
%%
%% Description: Sets options
%%--------------------------------------------------------------------
-setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
+setopts(#sslsocket{pid = [Pid, Sender]}, Options0) when is_pid(Pid), is_list(Options0) ->
+ try proplists:expand([{binary, [{mode, binary}]},
+ {list, [{mode, list}]}], Options0) of
+ Options ->
+ case proplists:get_value(packet, Options, undefined) of
+ undefined ->
+ ssl_connection:set_opts(Pid, Options);
+ PacketOpt ->
+ case tls_sender:setopts(Sender, [{packet, PacketOpt}]) of
+ ok ->
+ ssl_connection:set_opts(Pid, Options);
+ Error ->
+ Error
+ end
+ end
+ catch
+ _:_ ->
+ {error, {options, {not_a_proplist, Options0}}}
+ end;
+setopts(#sslsocket{pid = [Pid|_]}, Options0) when is_pid(Pid), is_list(Options0) ->
try proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Options0) of
Options ->
@@ -540,7 +1065,7 @@ setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
_:_ ->
{error, {options, {not_a_proplist, Options0}}}
end;
-setopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
+setopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
try dtls_socket:setopts(Transport, ListenSocket, Options) of
ok ->
ok;
@@ -550,7 +1075,7 @@ setopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = L
_:Error ->
{error, {options, {socket_options, Options, Error}}}
end;
-setopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
+setopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
try tls_socket:setopts(Transport, ListenSocket, Options) of
ok ->
ok;
@@ -564,9 +1089,9 @@ setopts(#sslsocket{}, Options) ->
{error, {options,{not_a_proplist, Options}}}.
%%---------------------------------------------------------------
--spec getstat(Socket) ->
- {ok, OptionValues} | {error, inet:posix()} when
- Socket :: #sslsocket{},
+-spec getstat(SslSocket) ->
+ {ok, OptionValues} | {error, inet:posix()} when
+ SslSocket :: sslsocket(),
OptionValues :: [{inet:stat_option(), integer()}].
%%
%% Description: Get all statistic options for a socket.
@@ -575,9 +1100,9 @@ getstat(Socket) ->
getstat(Socket, inet:stats()).
%%---------------------------------------------------------------
--spec getstat(Socket, Options) ->
- {ok, OptionValues} | {error, inet:posix()} when
- Socket :: #sslsocket{},
+-spec getstat(SslSocket, Options) ->
+ {ok, OptionValues} | {error, inet:posix()} when
+ SslSocket :: sslsocket(),
Options :: [inet:stat_option()],
OptionValues :: [{inet:stat_option(), integer()}].
%%
@@ -586,73 +1111,100 @@ getstat(Socket) ->
getstat(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}, Options) when is_port(Listen), is_list(Options) ->
tls_socket:getstat(Transport, Listen, Options);
-getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) ->
+getstat(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) ->
tls_socket:getstat(Transport, Socket, Options).
%%---------------------------------------------------------------
--spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
+-spec shutdown(SslSocket, How) -> ok | {error, reason()} when
+ SslSocket :: sslsocket(),
+ How :: read | write | read_write.
%%
%% Description: Same as gen_tcp:shutdown/2
%%--------------------------------------------------------------------
-shutdown(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_, _, _}}}},
+shutdown(#sslsocket{pid = {Listen, #config{transport_info = Info}}},
How) when is_port(Listen) ->
+ Transport = element(1, Info),
Transport:shutdown(Listen, How);
-shutdown(#sslsocket{pid = {udp,_}},_) ->
+shutdown(#sslsocket{pid = {dtls,_}},_) ->
{error, enotconn};
-shutdown(#sslsocket{pid = Pid}, How) ->
+shutdown(#sslsocket{pid = [Pid|_]}, How) when is_pid(Pid) ->
ssl_connection:shutdown(Pid, How).
%%--------------------------------------------------------------------
--spec sockname(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
+-spec sockname(SslSocket) ->
+ {ok, {Address, Port}} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Address :: inet:ip_address(),
+ Port :: inet:port_number().
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
-sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}) when is_port(Listen) ->
+sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_,_,_,_}}}}) when is_port(Listen) ->
tls_socket:sockname(Transport, Listen);
-sockname(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
- dtls_udp_listener:sockname(Pid);
-sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid) ->
+sockname(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
+ dtls_packet_demux:sockname(Pid);
+sockname(#sslsocket{pid = [Pid|_], fd = {Transport, Socket,_}}) when is_pid(Pid) ->
dtls_socket:sockname(Transport, Socket);
-sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid) ->
+sockname(#sslsocket{pid = [Pid| _], fd = {Transport, Socket,_,_}}) when is_pid(Pid) ->
tls_socket:sockname(Transport, Socket).
%%---------------------------------------------------------------
--spec versions() -> [{ssl_app, string()} | {supported, [tls_record:tls_atom_version()]} |
- {available, [tls_record:tls_atom_version()]}].
+-spec versions() -> [VersionInfo] when
+ VersionInfo :: {ssl_app, string()} |
+ {supported | available, [tls_version()]} |
+ {supported_dtls | available_dtls, [dtls_version()]}.
%%
%% Description: Returns a list of relevant versions.
%%--------------------------------------------------------------------
versions() ->
- Vsns = tls_record:supported_protocol_versions(),
- SupportedVsns = [tls_record:protocol_version(Vsn) || Vsn <- Vsns],
- AvailableVsns = ?ALL_AVAILABLE_VERSIONS,
- %% TODO Add DTLS versions when supported
- [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}].
+ TLSVsns = tls_record:supported_protocol_versions(),
+ DTLSVsns = dtls_record:supported_protocol_versions(),
+ SupportedTLSVsns = [tls_record:protocol_version(Vsn) || Vsn <- TLSVsns],
+ SupportedDTLSVsns = [dtls_record:protocol_version(Vsn) || Vsn <- DTLSVsns],
+ AvailableTLSVsns = ?ALL_AVAILABLE_VERSIONS,
+ AvailableDTLSVsns = ?ALL_AVAILABLE_DATAGRAM_VERSIONS,
+ [{ssl_app, "9.2"}, {supported, SupportedTLSVsns},
+ {supported_dtls, SupportedDTLSVsns},
+ {available, AvailableTLSVsns},
+ {available_dtls, AvailableDTLSVsns}].
%%---------------------------------------------------------------
--spec renegotiate(#sslsocket{}) -> ok | {error, reason()}.
+-spec renegotiate(SslSocket) -> ok | {error, reason()} when
+ SslSocket :: sslsocket().
%%
%% Description: Initiates a renegotiation.
%%--------------------------------------------------------------------
-renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+renegotiate(#sslsocket{pid = [Pid, Sender |_]}) when is_pid(Pid),
+ is_pid(Sender) ->
+ case tls_sender:renegotiate(Sender) of
+ {ok, Write} ->
+ tls_connection:renegotiation(Pid, Write);
+ Error ->
+ Error
+ end;
+renegotiate(#sslsocket{pid = [Pid |_]}) when is_pid(Pid) ->
ssl_connection:renegotiation(Pid);
-renegotiate(#sslsocket{pid = {udp,_}}) ->
+renegotiate(#sslsocket{pid = {dtls,_}}) ->
{error, enotconn};
renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
%%--------------------------------------------------------------------
--spec prf(#sslsocket{}, binary() | 'master_secret', binary(),
- [binary() | prf_random()], non_neg_integer()) ->
- {ok, binary()} | {error, reason()}.
+-spec prf(SslSocket, Secret, Label, Seed, WantedLength) ->
+ {ok, binary()} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Secret :: binary() | 'master_secret',
+ Label::binary(),
+ Seed :: [binary() | prf_random()],
+ WantedLength :: non_neg_integer().
%%
%% Description: use a ssl sessions TLS PRF to generate key material
%%--------------------------------------------------------------------
-prf(#sslsocket{pid = Pid},
+prf(#sslsocket{pid = [Pid|_]},
Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength);
-prf(#sslsocket{pid = {udp,_}}, _,_,_,_) ->
+prf(#sslsocket{pid = {dtls,_}}, _,_,_,_) ->
{error, enotconn};
prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
{error, enotconn}.
@@ -666,7 +1218,8 @@ clear_pem_cache() ->
ssl_pem_cache:clear().
%%---------------------------------------------------------------
--spec format_error({error, term()}) -> list().
+-spec format_error({error, Reason}) -> string() when
+ Reason :: any().
%%
%% Description: Creates error string.
%%--------------------------------------------------------------------
@@ -676,8 +1229,8 @@ format_error(Reason) when is_list(Reason) ->
Reason;
format_error(closed) ->
"TLS connection is closed";
-format_error({tls_alert, Description}) ->
- "TLS Alert: " ++ Description;
+format_error({tls_alert, {_, Description}}) ->
+ Description;
format_error({options,{FileType, File, Reason}}) when FileType == cacertfile;
FileType == certfile;
FileType == keyfile;
@@ -704,10 +1257,26 @@ tls_version({3, _} = Version) ->
tls_version({254, _} = Version) ->
dtls_v1:corresponding_tls_version(Version).
+
+%%--------------------------------------------------------------------
+-spec suite_to_str(CipherSuite) -> string() when
+ CipherSuite :: erl_cipher_suite();
+ (CipherSuite) -> string() when
+ %% For internal use!
+ CipherSuite :: #{key_exchange := null,
+ cipher := null,
+ mac := null,
+ prf := null}.
+%%
+%% Description: Return the string representation of a cipher suite.
+%%--------------------------------------------------------------------
+suite_to_str(Cipher) ->
+ ssl_cipher_format:suite_to_str(Cipher).
+
+
%%%--------------------------------------------------------------
%%% Internal functions
%%%--------------------------------------------------------------------
-
%% Possible filters out suites not supported by crypto
available_suites(default) ->
Version = tls_record:highest_protocol_version([]),
@@ -723,11 +1292,11 @@ supported_suites(all, Version) ->
supported_suites(anonymous, Version) ->
ssl_cipher:anonymous_suites(Version).
-do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, tls_connection) ->
+do_listen(Port, #config{transport_info = {Transport, _, _, _,_}} = Config, tls_connection) ->
tls_socket:listen(Transport, Port, Config);
-do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, dtls_connection) ->
- dtls_socket:listen(Transport, Port, Config).
+do_listen(Port, Config, dtls_connection) ->
+ dtls_socket:listen(Port, Config).
%% Handle extra ssl options given to ssl_accept
-spec handle_options([any()], #ssl_options{}) -> #ssl_options{}
@@ -775,15 +1344,12 @@ handle_options(Opts0, Role, Host) ->
{list, [{mode, list}]}], Opts0),
assert_proplist(Opts),
RecordCb = record_cb(Opts),
-
- ReuseSessionFun = fun(_, _, _, _) -> true end,
CaCerts = handle_option(cacerts, Opts, undefined),
{Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun, PartialChainHanlder, VerifyClientOnce} =
handle_verify_options(Opts, CaCerts),
CertFile = handle_option(certfile, Opts, <<>>),
- RecordCb = record_cb(Opts),
Versions = case handle_option(versions, Opts, []) of
[] ->
@@ -829,10 +1395,9 @@ handle_options(Opts0, Role, Host) ->
default_option_role(server,
tls_v1:default_signature_algs(Versions), Role)),
tls_version(RecordCb:highest_protocol_version(Versions))),
- %% Server side option
- reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
- reuse_sessions = handle_option(reuse_sessions, Opts, true),
- secure_renegotiate = handle_option(secure_renegotiate, Opts, false),
+ reuse_sessions = handle_reuse_sessions_option(reuse_sessions, Opts, Role),
+ reuse_session = handle_reuse_session_option(reuse_session, Opts, Role),
+ secure_renegotiate = handle_option(secure_renegotiate, Opts, true),
client_renegotiation = handle_option(client_renegotiation, Opts,
default_option_role(server, true, Role),
server, Role),
@@ -870,11 +1435,12 @@ handle_options(Opts0, Role, Host) ->
client, Role),
crl_check = handle_option(crl_check, Opts, false),
crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}}),
- v2_hello_compatible = handle_option(v2_hello_compatible, Opts, false),
- max_handshake_size = handle_option(max_handshake_size, Opts, ?DEFAULT_MAX_HANDSHAKE_SIZE)
+ max_handshake_size = handle_option(max_handshake_size, Opts, ?DEFAULT_MAX_HANDSHAKE_SIZE),
+ handshake = handle_option(handshake, Opts, full),
+ customize_hostname_check = handle_option(customize_hostname_check, Opts, [])
},
- CbInfo = proplists:get_value(cb_info, Opts, default_cb_info(Protocol)),
+ CbInfo = handle_option(cb_info, Opts, default_cb_info(Protocol)),
SslOptions = [protocol, versions, verify, verify_fun, partial_chain,
fail_if_no_peer_cert, verify_client_once,
depth, cert, certfile, key, keyfile,
@@ -886,9 +1452,8 @@ handle_options(Opts0, Role, Host) ->
alpn_preferred_protocols, next_protocols_advertised,
client_preferred_next_protocols, log_alert,
server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache,
- fallback, signature_algs, eccs, honor_ecc_order, beast_mitigation, v2_hello_compatible,
- max_handshake_size],
-
+ fallback, signature_algs, eccs, honor_ecc_order,
+ beast_mitigation, max_handshake_size, handshake, customize_hostname_check],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
end, Opts, SslOptions),
@@ -900,8 +1465,6 @@ handle_options(Opts0, Role, Host) ->
inet_user = Sock, transport_info = CbInfo, connection_cb = ConnetionCb
}}.
-
-
handle_option(OptionName, Opts, Default, Role, Role) ->
handle_option(OptionName, Opts, Default);
handle_option(_, _, undefined = Value, _, _) ->
@@ -919,6 +1482,10 @@ handle_option(sni_fun, Opts, Default) ->
_ ->
throw({error, {conflict_options, [sni_fun, sni_hosts]}})
end;
+handle_option(cb_info, Opts, Default) ->
+ CbInfo = proplists:get_value(cb_info, Opts, Default),
+ true = validate_option(cb_info, CbInfo),
+ handle_cb_info(CbInfo, Default);
handle_option(OptionName, Opts, Default) ->
validate_option(OptionName,
proplists:get_value(OptionName, Opts, Default)).
@@ -1024,11 +1591,16 @@ validate_option(srp_identity, {Username, Password})
{unicode:characters_to_binary(Username),
unicode:characters_to_binary(Password)};
+validate_option(reuse_session, undefined) ->
+ undefined;
validate_option(reuse_session, Value) when is_function(Value) ->
Value;
+validate_option(reuse_session, Value) when is_binary(Value) ->
+ Value;
validate_option(reuse_sessions, Value) when is_boolean(Value) ->
Value;
-
+validate_option(reuse_sessions, save = Value) ->
+ Value;
validate_option(secure_renegotiate, Value) when is_boolean(Value) ->
Value;
validate_option(client_renegotiation, Value) when is_boolean(Value) ->
@@ -1123,17 +1695,41 @@ validate_option(beast_mitigation, Value) when Value == one_n_minus_one orelse
Value == zero_n orelse
Value == disabled ->
Value;
-validate_option(v2_hello_compatible, Value) when is_boolean(Value) ->
- Value;
validate_option(max_handshake_size, Value) when is_integer(Value) andalso Value =< ?MAX_UNIT24 ->
Value;
validate_option(protocol, Value = tls) ->
Value;
validate_option(protocol, Value = dtls) ->
Value;
+validate_option(handshake, hello = Value) ->
+ Value;
+validate_option(handshake, full = Value) ->
+ Value;
+validate_option(customize_hostname_check, Value) when is_list(Value) ->
+ Value;
+validate_option(cb_info, {V1, V2, V3, V4}) when is_atom(V1),
+ is_atom(V2),
+ is_atom(V3),
+ is_atom(V4)
+ ->
+ true;
+validate_option(cb_info, {V1, V2, V3, V4, V5}) when is_atom(V1),
+ is_atom(V2),
+ is_atom(V3),
+ is_atom(V4),
+ is_atom(V5)
+ ->
+ true;
+validate_option(cb_info, _) ->
+ false;
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")};
+handle_cb_info(CbInfo, _) ->
+ CbInfo.
+
handle_hashsigns_option(Value, Version) when is_list(Value)
andalso Version >= {3, 3} ->
case tls_v1:signature_algs(Version, Value) of
@@ -1147,6 +1743,26 @@ handle_hashsigns_option(_, Version) when Version >= {3, 3} ->
handle_hashsigns_option(_, _Version) ->
undefined.
+handle_reuse_sessions_option(Key, Opts, client) ->
+ Value = proplists:get_value(Key, Opts, true),
+ validate_option(Key, Value),
+ Value;
+handle_reuse_sessions_option(Key, Opts0, server) ->
+ Opts = proplists:delete({Key, save}, Opts0),
+ Value = proplists:get_value(Key, Opts, true),
+ validate_option(Key, Value),
+ Value.
+
+handle_reuse_session_option(Key, Opts, client) ->
+ Value = proplists:get_value(Key, Opts, undefined),
+ validate_option(Key, Value),
+ Value;
+handle_reuse_session_option(Key, Opts, server) ->
+ ReuseSessionFun = fun(_, _, _, _) -> true end,
+ Value = proplists:get_value(Key, Opts, ReuseSessionFun),
+ validate_option(Key, Value),
+ Value.
+
validate_options([]) ->
[];
validate_options([{Opt, Value} | Tail]) ->
@@ -1234,10 +1850,10 @@ binary_cipher_suites(Version, []) ->
%% not require explicit configuration
default_binary_suites(Version);
binary_cipher_suites(Version, [Map|_] = Ciphers0) when is_map(Map) ->
- Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
+ Ciphers = [ssl_cipher_format:suite(C) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, [Tuple|_] = Ciphers0) when is_tuple(Tuple) ->
- Ciphers = [ssl_cipher:suite(tuple_to_map(C)) || C <- Ciphers0],
+ Ciphers = [ssl_cipher_format:suite(tuple_to_map(C)) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
All = ssl_cipher:all_suites(Version) ++
@@ -1252,11 +1868,11 @@ binary_cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0)
end;
binary_cipher_suites(Version, [Head | _] = Ciphers0) when is_list(Head) ->
%% Format: ["RC4-SHA","RC4-MD5"]
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- Ciphers0],
+ Ciphers = [ssl_cipher_format:openssl_suite(C) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, Ciphers0) ->
%% Format: "RC4-SHA:RC4-MD5"
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- string:lexemes(Ciphers0, ":")],
+ Ciphers = [ssl_cipher_format:openssl_suite(C) || C <- string:lexemes(Ciphers0, ":")],
binary_cipher_suites(Version, Ciphers).
default_binary_suites(Version) ->
@@ -1524,7 +2140,7 @@ default_option_role(_,_,_) ->
undefined.
default_cb_info(tls) ->
- {gen_tcp, tcp, tcp_closed, tcp_error};
+ {gen_tcp, tcp, tcp_closed, tcp_error, tcp_passive};
default_cb_info(dtls) ->
{gen_udp, udp, udp_closed, udp_error}.