aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src')
-rw-r--r--lib/ssl/src/Makefile25
-rw-r--r--lib/ssl/src/dtls.erl (renamed from lib/ssl/src/ssl_debug.hrl)28
-rw-r--r--lib/ssl/src/dtls_connection.erl19
-rw-r--r--lib/ssl/src/dtls_handshake.erl18
-rw-r--r--lib/ssl/src/dtls_handshake.hrl50
-rw-r--r--lib/ssl/src/dtls_record.erl18
-rw-r--r--lib/ssl/src/dtls_record.hrl44
-rw-r--r--lib/ssl/src/ssl.app.src25
-rw-r--r--lib/ssl/src/ssl.erl934
-rw-r--r--lib/ssl/src/ssl_certificate.erl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl32
-rw-r--r--lib/ssl/src/ssl_connection_sup.erl6
-rw-r--r--lib/ssl/src/ssl_handshake.hrl23
-rw-r--r--lib/ssl/src/ssl_manager.erl31
-rw-r--r--lib/ssl/src/ssl_pkix_db.erl (renamed from lib/ssl/src/ssl_certificate_db.erl)2
-rw-r--r--lib/ssl/src/ssl_record.hrl30
-rw-r--r--lib/ssl/src/ssl_srp_primes.hrl1
-rw-r--r--lib/ssl/src/ssl_tls1.erl62
-rw-r--r--lib/ssl/src/tls.erl1037
-rw-r--r--lib/ssl/src/tls_connection.erl (renamed from lib/ssl/src/ssl_connection.erl)197
-rw-r--r--lib/ssl/src/tls_handshake.erl (renamed from lib/ssl/src/ssl_handshake.erl)71
-rw-r--r--lib/ssl/src/tls_handshake.hrl45
-rw-r--r--lib/ssl/src/tls_record.erl (renamed from lib/ssl/src/ssl_record.erl)9
-rw-r--r--lib/ssl/src/tls_record.hrl39
24 files changed, 1609 insertions, 1139 deletions
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index d3ba76d34e..cf9f7d5001 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -42,31 +42,37 @@ BEHAVIOUR_MODULES= \
MODULES= \
ssl \
+ tls \
+ dtls \
ssl_alert \
ssl_app \
ssl_dist_sup\
ssl_sup \
inet_tls_dist \
ssl_certificate\
- ssl_certificate_db\
+ ssl_pkix_db\
ssl_cipher \
ssl_srp_primes \
- ssl_connection \
+ tls_connection \
+ dtls_connection \
ssl_connection_sup \
- ssl_handshake \
+ tls_handshake \
+ dtls_handshake\
ssl_manager \
ssl_session \
ssl_session_cache \
ssl_socket \
- ssl_record \
+ tls_record \
+ dtls_record \
ssl_ssl2 \
ssl_ssl3 \
ssl_tls1 \
ssl_tls_dist_proxy
INTERNAL_HRL_FILES = \
- ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \
- ssl_record.hrl ssl_srp.hrl ssl_srp_primes.hrl
+ ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl tls_handshake.hrl \
+ dtls_handshake.hrl ssl_internal.hrl \
+ ssl_record.hrl tls_record.hrl dtls_record.hrl ssl_srp.hrl
ERL_FILES= \
$(MODULES:%=%.erl) \
@@ -134,13 +140,14 @@ release_docs_spec:
# Dependencies
# ----------------------------------------------------
$(EBIN)/inet_tls_dist.$(EMULATOR): ../../kernel/include/net_address.hrl ../../kernel/include/dist.hrl ../../kernel/include/dist_util.hrl
-$(EBIN)/ssl.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/tls.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
$(EBIN)/ssl_alert.$(EMULATOR): ssl_alert.hrl ssl_record.hrl
$(EBIN)/ssl_certificate.$(EMULATOR): ssl_internal.hrl ssl_alert.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
$(EBIN)/ssl_certificate_db.$(EMULATOR): ssl_internal.hrl ../../public_key/include/public_key.hrl ../../kernel/include/file.hrl
$(EBIN)/ssl_cipher.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/ssl_connection.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/ssl_handshake.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/tls_connection.$(EMULATOR): ssl_internal.hrl tls_record.hrl ssl_cipher.hrl tls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/dtls_connection.$(EMULATOR): ssl_internal.hrl dtls_record.hrl ssl_cipher.hrl dtls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/tls_handshake.$(EMULATOR): ssl_internal.hrl tls_record.hrl ssl_cipher.hrl tls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
$(EBIN)/ssl_manager.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl ../../kernel/include/file.hrl
$(EBIN)/ssl_record.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl
$(EBIN)/ssl_session.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl
diff --git a/lib/ssl/src/ssl_debug.hrl b/lib/ssl/src/dtls.erl
index e88cef441f..013286c9bd 100644
--- a/lib/ssl/src/ssl_debug.hrl
+++ b/lib/ssl/src/dtls.erl
@@ -1,39 +1,25 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
+%%% Purpose : API for DTLS.
--ifndef(ssl_debug).
--define(ssl_debug, true).
-
--ifdef(SSL_DEBUG).
--define(DBG_HEX(V), ssl_debug:hex_data(??V, V, ?MODULE, ?LINE)).
--define(DBG_TERM(T), ssl_debug:term_data(??T, T, ?MODULE, ?LINE)).
--else.
--define(DBG_HEX(V), ok).
--define(DBG_TERM(T), ok).
--endif.
-
--endif. % -ifdef(ssl_debug).
-
-
-
-
+-module(dtls).
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
new file mode 100644
index 0000000000..ac2ee0d09f
--- /dev/null
+++ b/lib/ssl/src/dtls_connection.erl
@@ -0,0 +1,19 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(dtls_connection).
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
new file mode 100644
index 0000000000..b25daa59d9
--- /dev/null
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -0,0 +1,18 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+-module(dtls_handshake).
diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl
new file mode 100644
index 0000000000..db7b8596ae
--- /dev/null
+++ b/lib/ssl/src/dtls_handshake.hrl
@@ -0,0 +1,50 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the DTLS-handshake protocol
+%% that differs from TLS see RFC 6347
+%%----------------------------------------------------------------------
+-ifndef(dtls_handshake).
+-define(dtls_handshake, true).
+
+-include("ssl_handshake.hrl"). %% Common TLS and DTLS records and Constantes
+
+-record(client_hello, {
+ client_version,
+ random,
+ session_id, % opaque SessionID<0..32>
+ cookie, % opaque<2..2^16-1>
+ cipher_suites, % cipher_suites<2..2^16-1>
+ compression_methods, % compression_methods<1..2^8-1>,
+ %% Extensions
+ renegotiation_info,
+ hash_signs, % supported combinations of hashes/signature algos
+ next_protocol_negotiation = undefined % [binary()]
+ }).
+
+-record(hello_verify_request {
+ protocol_version,
+ cookie
+ }).
+
+-define(HELLO_VERIFY_REQUEST, 3).
+
+-endif. % -ifdef(dtls_handshake).
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
new file mode 100644
index 0000000000..2469a7d26c
--- /dev/null
+++ b/lib/ssl/src/dtls_record.erl
@@ -0,0 +1,18 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+-module(dtls_record).
diff --git a/lib/ssl/src/dtls_record.hrl b/lib/ssl/src/dtls_record.hrl
new file mode 100644
index 0000000000..e935d84bdf
--- /dev/null
+++ b/lib/ssl/src/dtls_record.hrl
@@ -0,0 +1,44 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the DTLS-record protocol
+%% see RFC 6347
+%%----------------------------------------------------------------------
+
+-ifndef(dtls_record).
+-define(dtls_record, true).
+
+-include("ssl_record.hrl"). %% Common TLS and DTLS records and Constantes
+
+%% Used to handle tls_plain_text, tls_compressed and tls_cipher_text
+
+-record(ssl_tls, {
+ type,
+ version,
+ record_seq, % used in plain_text
+ epoch, % used in plain_text
+ message_seq,
+ fragment_offset,
+ fragment_length,
+ fragment
+ }).
+
+-endif. % -ifdef(dtls_record).
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 5c34de905e..582a60635f 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -1,7 +1,20 @@
{application, ssl,
[{description, "Erlang/OTP SSL application"},
{vsn, "%VSN%"},
- {modules, [ssl,
+ {modules, [
+ %% TLS/SSL
+ tls,
+ tls_connection,
+ tls_handshake,
+ tls_record,
+ %% DTLS
+ dtls_record,
+ dtls_handshake,
+ dtls_connection,
+ dtls,
+ %% Backwards compatibility
+ ssl,
+ %% Both TLS/SSL and DTLS
ssl_app,
ssl_sup,
inet_tls_dist,
@@ -14,14 +27,14 @@
ssl_session_cache_api,
ssl_session_cache,
ssl_socket,
- ssl_record,
+ %%ssl_record,
ssl_manager,
- ssl_handshake,
+ %%ssl_handshake,
ssl_connection_sup,
- ssl_connection,
+ %%ssl_connection,
ssl_cipher,
ssl_srp_primes,
- ssl_certificate_db,
+ ssl_pkix_db,
ssl_certificate,
ssl_alert
]},
@@ -31,5 +44,3 @@
{mod, {ssl_app, []}}]}.
-
-
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index f52862729a..75c17b14db 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -19,7 +19,7 @@
%%
-%%% Purpose : Main API module for SSL.
+%%% Purpose : Backwards compatibility
-module(ssl).
@@ -37,7 +37,6 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_handshake.hrl").
--include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -47,13 +46,6 @@
tls_atom_version/0, %% From ssl_internal.hrl
prf_random/0, sslsocket/0]).
--record(config, {ssl, %% SSL parameters
- inet_user, %% User set inet options
- emulated, %% #socket_option{} emulated
- inet_ssl, %% inet options for internal ssl socket
- cb %% Callback info
- }).
-
-type sslsocket() :: #sslsocket{}.
-type connect_option() :: socket_connect_option() | ssl_option() | transport_option().
-type socket_connect_option() :: gen_tcp:connect_option().
@@ -93,241 +85,65 @@
%% is temporary. see application(3)
%%--------------------------------------------------------------------
start() ->
- application:start(crypto),
- application:start(public_key),
- application:start(ssl).
-
+ tls:start().
start(Type) ->
- application:start(crypto, Type),
- application:start(public_key, Type),
- application:start(ssl, Type).
+ tls:start(Type).
-%%--------------------------------------------------------------------
--spec stop() -> ok.
-%%
-%% Description: Stops the ssl application.
-%%--------------------------------------------------------------------
stop() ->
- application:stop(ssl).
+ tls:stop().
-%%--------------------------------------------------------------------
--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()}.
+connect(Socket, SslOptions) ->
+ tls:connect(Socket, SslOptions).
-%%
-%% Description: Connect to an ssl server.
-%%--------------------------------------------------------------------
-connect(Socket, SslOptions) when is_port(Socket) ->
- connect(Socket, SslOptions, infinity).
-
-connect(Socket, SslOptions0, Timeout) when is_port(Socket) ->
- {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0,
- {gen_tcp, tcp, tcp_closed, tcp_error}),
- EmulatedOptions = emulated_options(),
- {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
- try handle_options(SslOptions0 ++ SocketValues, client) of
- {ok, #config{cb = CbInfo, ssl = SslOptions, emulated = EmOpts}} ->
-
- ok = ssl_socket:setopts(Transport, Socket, internal_inet_values()),
- case ssl_socket:peername(Transport, Socket) of
- {ok, {Address, Port}} ->
- ssl_connection:connect(Address, Port, Socket,
- {SslOptions, EmOpts},
- self(), CbInfo, Timeout);
- {error, Error} ->
- {error, Error}
- end
- catch
- _:{error, Reason} ->
- {error, Reason}
- end;
-
-connect(Host, Port, Options) ->
- connect(Host, Port, Options, infinity).
+connect(Socket, SslOptions0, TimeoutOrOpts) ->
+ tls:connect(Socket, SslOptions0, TimeoutOrOpts).
connect(Host, Port, Options, Timeout) ->
- try handle_options(Options, client) of
- {ok, Config} ->
- do_connect(Host,Port,Config,Timeout)
- catch
- throw:Error ->
- Error
- end.
+ tls:connect(Host, Port, Options, Timeout).
-%%--------------------------------------------------------------------
--spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
-
-%%
-%% Description: Creates an ssl listen socket.
-%%--------------------------------------------------------------------
-listen(_Port, []) ->
- {error, nooptions};
-listen(Port, Options0) ->
- try
- {ok, Config} = handle_options(Options0, server),
- #config{cb = {Transport, _, _, _}, inet_user = Options} = Config,
- case Transport:listen(Port, Options) of
- {ok, ListenSocket} ->
- {ok, #sslsocket{pid = {ListenSocket, Config}}};
- Err = {error, _} ->
- Err
- end
- catch
- Error = {error, _} ->
- 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
-%%--------------------------------------------------------------------
-transport_accept(ListenSocket) ->
- transport_accept(ListenSocket, infinity).
+listen(Port, Options) ->
+ tls:listen(Port, Options).
-transport_accept(#sslsocket{pid = {ListenSocket, #config{cb = CbInfo, ssl = SslOpts}}}, Timeout) ->
-
- %% The setopt could have been invoked on the listen socket
- %% and options should be inherited.
- EmOptions = emulated_options(),
- {Transport,_,_, _} = CbInfo,
- {ok, SocketValues} = ssl_socket:getopts(Transport, ListenSocket, EmOptions),
- ok = ssl_socket:setopts(Transport, ListenSocket, internal_inet_values()),
- case Transport:accept(ListenSocket, Timeout) of
- {ok, Socket} ->
- ok = ssl_socket:setopts(Transport, ListenSocket, SocketValues),
- {ok, Port} = ssl_socket:port(Transport, Socket),
- ConnArgs = [server, "localhost", Port, Socket,
- {SslOpts, socket_options(SocketValues)}, self(), CbInfo],
- case ssl_connection_sup:start_child(ConnArgs) of
- {ok, Pid} ->
- ssl_connection:socket_control(Socket, Pid, Transport);
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
+transport_accept(ListenSocket) ->
+ tls:transport_accept(ListenSocket).
-%%--------------------------------------------------------------------
--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(port(), [ssl_option()| transport_option()], timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-%%
-%% Description: Performs accept on an ssl listen socket. e.i. performs
-%% ssl handshake.
-%%--------------------------------------------------------------------
+transport_accept(ListenSocket, Timeout) ->
+ tls:transport_accept(ListenSocket, Timeout).
+
ssl_accept(ListenSocket) ->
- ssl_accept(ListenSocket, infinity).
+ tls:ssl_accept(ListenSocket, infinity).
ssl_accept(#sslsocket{} = Socket, Timeout) ->
- ssl_connection:handshake(Socket, Timeout);
+ tls:ssl_accept(Socket, Timeout);
ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
- ssl_accept(ListenSocket, SslOptions, infinity).
+ tls:ssl_accept(ListenSocket, SslOptions, infinity).
ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
- {Transport,_,_,_} =
- proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
- EmulatedOptions = emulated_options(),
- {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
- try handle_options(SslOptions ++ SocketValues, server) of
- {ok, #config{cb = CbInfo, ssl = SslOpts, emulated = EmOpts}} ->
- ok = ssl_socket:setopts(Transport, Socket, internal_inet_values()),
- {ok, Port} = ssl_socket:port(Transport, Socket),
- ssl_connection:ssl_accept(Port, Socket,
- {SslOpts, EmOpts},
- self(), CbInfo, Timeout)
- catch
- Error = {error, _Reason} -> Error
- end.
+ tls:ssl_accept(Socket, SslOptions, Timeout).
-%%--------------------------------------------------------------------
--spec close(#sslsocket{}) -> term().
-%%
-%% Description: Close an ssl connection
-%%--------------------------------------------------------------------
-close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- ssl_connection:close(Pid);
-close(#sslsocket{pid = {ListenSocket, #config{cb={Transport,_, _, _}}}}) ->
- Transport:close(ListenSocket).
+close(Socket) ->
+ tls:close(Socket).
-%%--------------------------------------------------------------------
--spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}.
-%%
-%% Description: Sends data over the ssl connection
-%%--------------------------------------------------------------------
-send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
- ssl_connection:send(Pid, Data);
-send(#sslsocket{pid = {ListenSocket, #config{cb={Transport, _, _, _}}}}, Data) ->
- Transport:send(ListenSocket, Data). %% {error,enotconn}
+send(Socket, Data) ->
+ tls:send(Socket, Data).
-%%--------------------------------------------------------------------
--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
-%%--------------------------------------------------------------------
recv(Socket, Length) ->
- recv(Socket, Length, infinity).
-recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid) ->
- ssl_connection:recv(Pid, Length, Timeout);
-recv(#sslsocket{pid = {Listen,
- #config{cb={Transport, _, _, _}}}}, _,_) when is_port(Listen)->
- Transport:recv(Listen, 0). %% {error,enotconn}
-
-%%--------------------------------------------------------------------
--spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
-%%
-%% 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) ->
- ssl_connection:new_user(Pid, NewOwner);
-controlling_process(#sslsocket{pid = {Listen,
- #config{cb={Transport, _, _, _}}}},
- NewOwner) when is_port(Listen),
- is_pid(NewOwner) ->
- Transport:controlling_process(Listen, NewOwner).
+ tls:recv(Socket, Length, infinity).
+recv(Socket, Length, Timeout) ->
+ tls:recv(Socket, Length, Timeout).
-%%--------------------------------------------------------------------
--spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
- {error, reason()}.
-%%
-%% Description: Returns ssl protocol and cipher used for the connection
-%%--------------------------------------------------------------------
-connection_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- ssl_connection:info(Pid);
-connection_info(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
- {error, enotconn}.
+controlling_process(Socket, NewOwner) ->
+ tls:controlling_process(Socket, NewOwner).
+
+connection_info(Socket) ->
+ tls:connection_info(Socket).
-%%--------------------------------------------------------------------
--spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
-%%
-%% Description: same as inet:peername/1.
-%%--------------------------------------------------------------------
-peername(#sslsocket{pid = Pid, fd = {Transport, Socket}}) when is_pid(Pid)->
- ssl_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}}) ->
- ssl_socket:peername(Transport, ListenSocket). %% Will return {error, enotconn}
+peername(Socket) ->
+ tls:peername(Socket).
-%%--------------------------------------------------------------------
--spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
-%%
-%% Description: Returns the peercert.
-%%--------------------------------------------------------------------
peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- case ssl_connection:peer_certificate(Pid) of
+ case tls_connection:peer_certificate(Pid) of
{ok, undefined} ->
{error, no_peercert};
Result ->
@@ -336,701 +152,71 @@ peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn}.
-%%--------------------------------------------------------------------
--spec suite_definition(cipher_suite()) -> erl_cipher_suite().
-%%
-%% Description: Return erlang cipher suite definition.
-%%--------------------------------------------------------------------
suite_definition(S) ->
{KeyExchange, Cipher, Hash, _} = ssl_cipher:suite_definition(S),
{KeyExchange, Cipher, Hash}.
-%%--------------------------------------------------------------------
--spec negotiated_next_protocol(#sslsocket{}) -> {ok, binary()} | {error, reason()}.
-%%
-%% Description: Returns the next protocol that has been negotiated. If no
-%% protocol has been negotiated will return {error, next_protocol_not_negotiated}
-%%--------------------------------------------------------------------
negotiated_next_protocol(#sslsocket{pid = Pid}) ->
- ssl_connection:negotiated_next_protocol(Pid).
+ tls_connection:negotiated_next_protocol(Pid).
+%%%--------------------------------------------------------------------
-spec cipher_suites() -> [erl_cipher_suite()].
-spec cipher_suites(erlang | openssl | all ) -> [erl_cipher_suite()] | [string()].
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
+
cipher_suites() ->
cipher_suites(erlang).
cipher_suites(erlang) ->
- Version = ssl_record:highest_protocol_version([]),
- [suite_definition(S) || S <- cipher_suites(Version, [])];
+ Version = tls_record:highest_protocol_version([]),
+ [suite_definition(S) || S <- ssl_cipher:suites(Version)];
cipher_suites(openssl) ->
- Version = ssl_record:highest_protocol_version([]),
- [ssl_cipher:openssl_suite_name(S) || S <- cipher_suites(Version, [])];
+ Version = tls_record:highest_protocol_version([]),
+ [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)];
cipher_suites(all) ->
- Version = ssl_record:highest_protocol_version([]),
+ Version = tls_record:highest_protocol_version([]),
Supported = ssl_cipher:suites(Version)
++ ssl_cipher:anonymous_suites()
++ ssl_cipher:psk_suites(Version)
++ ssl_cipher:srp_suites(),
[suite_definition(S) || S <- Supported].
-%%--------------------------------------------------------------------
--spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
- {ok, [gen_tcp:option()]} | {error, reason()}.
-%%
-%% Description: Gets options
-%%--------------------------------------------------------------------
-getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
- ssl_connection:get_opts(Pid, OptionTags);
-getopts(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}},
- OptionTags) when is_list(OptionTags) ->
- try ssl_socket:getopts(Transport, ListenSocket, OptionTags) of
- {ok, _} = Result ->
- Result;
- {error, InetError} ->
- {error, {options, {socket_options, OptionTags, InetError}}}
- catch
- _:_ ->
- {error, {options, {socket_options, OptionTags}}}
- end;
-getopts(#sslsocket{}, OptionTags) ->
- {error, {options, {socket_options, OptionTags}}}.
-
-%%--------------------------------------------------------------------
--spec setopts(#sslsocket{}, [gen_tcp:option()]) -> ok | {error, reason()}.
-%%
-%% Description: Sets options
-%%--------------------------------------------------------------------
-setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
- try proplists:expand([{binary, [{mode, binary}]},
- {list, [{mode, list}]}], Options0) of
- Options ->
- ssl_connection:set_opts(Pid, Options)
- catch
- _:_ ->
- {error, {options, {not_a_proplist, Options0}}}
- end;
-setopts(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}}, Options) when is_list(Options) ->
- try ssl_socket:setopts(Transport, ListenSocket, Options) of
- ok ->
- ok;
- {error, InetError} ->
- {error, {options, {socket_options, Options, InetError}}}
- catch
- _:Error ->
- {error, {options, {socket_options, Options, Error}}}
- end;
-setopts(#sslsocket{}, Options) ->
- {error, {options,{not_a_proplist, Options}}}.
+getopts(Socket, OptionTags) ->
+ tls:getopts(Socket, OptionTags).
-%%---------------------------------------------------------------
--spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
-%%
-%% Description: Same as gen_tcp:shutdown/2
-%%--------------------------------------------------------------------
-shutdown(#sslsocket{pid = {Listen, #config{cb={Transport,_, _, _}}}},
- How) when is_port(Listen) ->
- Transport:shutdown(Listen, How);
-shutdown(#sslsocket{pid = Pid}, How) ->
- ssl_connection:shutdown(Pid, How).
+setopts(Socket, Options) ->
+ tls:setopts(Socket, Options).
-%%--------------------------------------------------------------------
--spec sockname(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
-%%
-%% Description: Same as inet:sockname/1
-%%--------------------------------------------------------------------
-sockname(#sslsocket{pid = {Listen, #config{cb={Transport,_, _, _}}}}) when is_port(Listen) ->
- ssl_socket:sockname(Transport, Listen);
+shutdown(Socket, How) ->
+ tls:shutdown(Socket, How).
-sockname(#sslsocket{pid = Pid, fd = {Transport, Socket}}) when is_pid(Pid) ->
- ssl_socket:sockname(Transport, Socket).
+sockname(Socket) ->
+ tls:sockname(Socket).
-%%---------------------------------------------------------------
--spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
-%%
-%% Description: Returns list of session info currently [{session_id, session_id(),
-%% {cipher_suite, cipher_suite()}]
-%%--------------------------------------------------------------------
session_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- ssl_connection:session_info(Pid);
+ tls_connection:session_info(Pid);
session_info(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
-%%---------------------------------------------------------------
--spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} |
- {available, [tls_atom_version()]}].
-%%
-%% Description: Returns a list of relevant versions.
-%%--------------------------------------------------------------------
versions() ->
- Vsns = ssl_record:supported_protocol_versions(),
- SupportedVsns = [ssl_record:protocol_version(Vsn) || Vsn <- Vsns],
- AvailableVsns = ?ALL_SUPPORTED_VERSIONS,
- [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}].
+ tls:versions().
+renegotiate(Socket) ->
+ tls:renegotiate(Socket).
-%%---------------------------------------------------------------
--spec renegotiate(#sslsocket{}) -> ok | {error, reason()}.
-%%
-%% Description: Initiates a renegotiation.
-%%--------------------------------------------------------------------
-renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- ssl_connection:renegotiation(Pid);
-renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
- {error, enotconn}.
+prf(Socket, Secret, Label, Seed, WantedLength) ->
+ tls:prf(Socket, Secret, Label, Seed, WantedLength).
-%%--------------------------------------------------------------------
--spec prf(#sslsocket{}, binary() | 'master_secret', binary(),
- binary() | prf_random(), non_neg_integer()) ->
- {ok, binary()} | {error, reason()}.
-%%
-%% Description: use a ssl sessions TLS PRF to generate key material
-%%--------------------------------------------------------------------
-prf(#sslsocket{pid = Pid},
- Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
- ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength);
-prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
- {error, enotconn}.
-
-%%--------------------------------------------------------------------
--spec clear_pem_cache() -> ok.
-%%
-%% Description: Clear the PEM cache
-%%--------------------------------------------------------------------
clear_pem_cache() ->
- ssl_manager:clear_pem_cache().
+ tls:clear_pem_cache().
-%%---------------------------------------------------------------
--spec format_error({error, term()}) -> list().
-%%
-%% Description: Creates error string.
-%%--------------------------------------------------------------------
-format_error({error, Reason}) ->
- format_error(Reason);
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({options,{FileType, File, Reason}}) when FileType == cacertfile;
- FileType == certfile;
- FileType == keyfile;
- FileType == dhfile ->
- Error = file_error_format(Reason),
- file_desc(FileType) ++ File ++ ": " ++ Error;
-format_error({options, {socket_options, Option, Error}}) ->
- lists:flatten(io_lib:format("Invalid transport socket option ~p: ~s", [Option, format_error(Error)]));
-format_error({options, {socket_options, Option}}) ->
- lists:flatten(io_lib:format("Invalid socket option: ~p", [Option]));
-format_error({options, Options}) ->
- lists:flatten(io_lib:format("Invalid TLS option: ~p", [Options]));
-
-format_error(Error) ->
- case inet:format_error(Error) of
- "unknown POSIX" ++ _ ->
- unexpected_format(Error);
- Other ->
- Other
- end.
+ tls:format_error(Reason).
-%%--------------------------------------------------------------------
--spec random_bytes(integer()) -> binary().
-
-%%
-%% Description: Generates cryptographically secure random sequence if possible
-%% fallbacks on pseudo random function
-%%--------------------------------------------------------------------
random_bytes(N) ->
- try crypto:strong_rand_bytes(N) of
- RandBytes ->
- RandBytes
- catch
- error:low_entropy ->
- crypto:rand_bytes(N)
- end.
-
-%%%--------------------------------------------------------------
-%%% Internal functions
-%%%--------------------------------------------------------------------
-do_connect(Address, Port,
- #config{cb=CbInfo, inet_user=UserOpts, ssl=SslOpts,
- emulated=EmOpts,inet_ssl=SocketOpts},
- Timeout) ->
- {Transport, _, _, _} = CbInfo,
- try Transport:connect(Address, Port, SocketOpts, Timeout) of
- {ok, Socket} ->
- ssl_connection:connect(Address, Port, Socket, {SslOpts,EmOpts},
- self(), CbInfo, Timeout);
- {error, Reason} ->
- {error, Reason}
- catch
- exit:{function_clause, _} ->
- {error, {options, {cb_info, CbInfo}}};
- exit:badarg ->
- {error, {options, {socket_options, UserOpts}}};
- exit:{badarg, _} ->
- {error, {options, {socket_options, UserOpts}}}
- end.
-
-handle_options(Opts0, _Role) ->
- Opts = proplists:expand([{binary, [{mode, binary}]},
- {list, [{mode, list}]}], Opts0),
- ReuseSessionFun = fun(_, _, _, _) -> true end,
-
- DefaultVerifyNoneFun =
- {fun(_,{bad_cert, _}, UserState) ->
- {valid, UserState};
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, UserState};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, []},
-
- VerifyNoneFun = handle_option(verify_fun, Opts, DefaultVerifyNoneFun),
-
- UserFailIfNoPeerCert = handle_option(fail_if_no_peer_cert, Opts, false),
- UserVerifyFun = handle_option(verify_fun, Opts, undefined),
- CaCerts = handle_option(cacerts, Opts, undefined),
-
- {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun} =
- %% Handle 0, 1, 2 for backwards compatibility
- case proplists:get_value(verify, Opts, verify_none) of
- 0 ->
- {verify_none, false,
- ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
- 1 ->
- {verify_peer, false,
- ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
- 2 ->
- {verify_peer, true,
- ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
- verify_none ->
- {verify_none, false,
- ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
- verify_peer ->
- {verify_peer, UserFailIfNoPeerCert,
- ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
- Value ->
- throw({error, {options, {verify, Value}}})
- end,
-
- CertFile = handle_option(certfile, Opts, <<>>),
-
- Versions = case handle_option(versions, Opts, []) of
- [] ->
- ssl_record:supported_protocol_versions();
- Vsns ->
- [ssl_record:protocol_version(Vsn) || Vsn <- Vsns]
- end,
-
- SSLOptions = #ssl_options{
- versions = Versions,
- verify = validate_option(verify, Verify),
- verify_fun = VerifyFun,
- fail_if_no_peer_cert = FailIfNoPeerCert,
- verify_client_once = handle_option(verify_client_once, Opts, false),
- depth = handle_option(depth, Opts, 1),
- cert = handle_option(cert, Opts, undefined),
- certfile = CertFile,
- key = handle_option(key, Opts, undefined),
- keyfile = handle_option(keyfile, Opts, CertFile),
- password = handle_option(password, Opts, ""),
- cacerts = CaCerts,
- cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
- dh = handle_option(dh, Opts, undefined),
- dhfile = handle_option(dhfile, Opts, undefined),
- user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
- psk_identity = handle_option(psk_identity, Opts, undefined),
- srp_identity = handle_option(srp_identity, Opts, undefined),
- ciphers = handle_option(ciphers, Opts, []),
- %% 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),
- renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT),
- hibernate_after = handle_option(hibernate_after, Opts, undefined),
- erl_dist = handle_option(erl_dist, Opts, false),
- next_protocols_advertised =
- handle_option(next_protocols_advertised, Opts, undefined),
- next_protocol_selector =
- make_next_protocol_selector(
- handle_option(client_preferred_next_protocols, Opts, undefined))
- },
-
- CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
- SslOptions = [versions, verify, verify_fun,
- fail_if_no_peer_cert, verify_client_once,
- depth, cert, certfile, key, keyfile,
- password, cacerts, cacertfile, dh, dhfile,
- user_lookup_fun, psk_identity, srp_identity, ciphers,
- reuse_session, reuse_sessions, ssl_imp,
- cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
- erl_dist, next_protocols_advertised,
- client_preferred_next_protocols],
-
- SockOpts = lists:foldl(fun(Key, PropList) ->
- proplists:delete(Key, PropList)
- end, Opts, SslOptions),
-
- {SSLsock, Emulated} = emulated_options(SockOpts),
- {ok, #config{ssl=SSLOptions, emulated=Emulated, inet_ssl=SSLsock,
- inet_user=SockOpts, cb=CbInfo}}.
-
-handle_option(OptionName, Opts, Default) ->
- validate_option(OptionName,
- proplists:get_value(OptionName, Opts, Default)).
-
-
-validate_option(versions, Versions) ->
- validate_versions(Versions, Versions);
-validate_option(verify, Value)
- when Value == verify_none; Value == verify_peer ->
- Value;
-validate_option(verify_fun, undefined) ->
- undefined;
-%% Backwards compatibility
-validate_option(verify_fun, Fun) when is_function(Fun) ->
- {fun(_,{bad_cert, _} = Reason, OldFun) ->
- case OldFun([Reason]) of
- true ->
- {valid, OldFun};
- false ->
- {fail, Reason}
- end;
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, UserState};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, Fun};
-validate_option(verify_fun, {Fun, _} = Value) when is_function(Fun) ->
- Value;
-validate_option(fail_if_no_peer_cert, Value)
- when Value == true; Value == false ->
- Value;
-validate_option(verify_client_once, Value)
- when Value == true; Value == false ->
- Value;
-validate_option(depth, Value) when is_integer(Value),
- Value >= 0, Value =< 255->
- Value;
-validate_option(cert, Value) when Value == undefined;
- is_binary(Value) ->
- Value;
-validate_option(certfile, undefined = Value) ->
- Value;
-validate_option(certfile, Value) when is_binary(Value) ->
- Value;
-validate_option(certfile, Value) when is_list(Value) ->
- list_to_binary(Value);
-
-validate_option(key, undefined) ->
- undefined;
-validate_option(key, {KeyType, Value}) when is_binary(Value),
- KeyType == rsa; %% Backwards compatibility
- KeyType == dsa; %% Backwards compatibility
- KeyType == 'RSAPrivateKey';
- KeyType == 'DSAPrivateKey';
- KeyType == 'ECPrivateKey';
- KeyType == 'PrivateKeyInfo' ->
- {KeyType, Value};
-
-validate_option(keyfile, undefined) ->
- <<>>;
-validate_option(keyfile, Value) when is_binary(Value) ->
- Value;
-validate_option(keyfile, Value) when is_list(Value), Value =/= "" ->
- list_to_binary(Value);
-validate_option(password, Value) when is_list(Value) ->
- Value;
-
-validate_option(cacerts, Value) when Value == undefined;
- is_list(Value) ->
- Value;
-%% certfile must be present in some cases otherwhise it can be set
-%% to the empty string.
-validate_option(cacertfile, undefined) ->
- <<>>;
-validate_option(cacertfile, Value) when is_binary(Value) ->
- Value;
-validate_option(cacertfile, Value) when is_list(Value), Value =/= ""->
- list_to_binary(Value);
-validate_option(dh, Value) when Value == undefined;
- is_binary(Value) ->
- Value;
-validate_option(dhfile, undefined = Value) ->
- Value;
-validate_option(dhfile, Value) when is_binary(Value) ->
- Value;
-validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
- list_to_binary(Value);
-validate_option(psk_identity, undefined) ->
- undefined;
-validate_option(psk_identity, Identity)
- when is_list(Identity), Identity =/= "", length(Identity) =< 65535 ->
- list_to_binary(Identity);
-validate_option(user_lookup_fun, undefined) ->
- undefined;
-validate_option(user_lookup_fun, {Fun, _} = Value) when is_function(Fun, 3) ->
- Value;
-validate_option(srp_identity, undefined) ->
- undefined;
-validate_option(srp_identity, {Username, Password})
- when is_list(Username), is_list(Password), Username =/= "", length(Username) =< 255 ->
- {list_to_binary(Username), list_to_binary(Password)};
-validate_option(ciphers, Value) when is_list(Value) ->
- Version = ssl_record:highest_protocol_version([]),
- try cipher_suites(Version, Value)
- catch
- exit:_ ->
- throw({error, {options, {ciphers, Value}}});
- error:_->
- throw({error, {options, {ciphers, Value}}})
- end;
-validate_option(reuse_session, Value) when is_function(Value) ->
- Value;
-validate_option(reuse_sessions, Value) when Value == true;
- Value == false ->
- Value;
-
-validate_option(secure_renegotiate, Value) when Value == true;
- Value == false ->
- Value;
-validate_option(renegotiate_at, Value) when is_integer(Value) ->
- erlang:min(Value, ?DEFAULT_RENEGOTIATE_AT);
-
-validate_option(hibernate_after, undefined) ->
- undefined;
-validate_option(hibernate_after, Value) when is_integer(Value), Value >= 0 ->
- Value;
-validate_option(erl_dist,Value) when Value == true;
- Value == false ->
- Value;
-validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols} = Value)
- when is_list(PreferredProtocols) ->
- case ssl_record:highest_protocol_version([]) of
- {3,0} ->
- throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
- _ ->
- validate_binary_list(client_preferred_next_protocols, PreferredProtocols),
- validate_npn_ordering(Precedence),
- {Precedence, PreferredProtocols, ?NO_PROTOCOL}
- end;
-validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols, Default} = Value)
- when is_list(PreferredProtocols), is_binary(Default),
- byte_size(Default) > 0, byte_size(Default) < 256 ->
- case ssl_record:highest_protocol_version([]) of
- {3,0} ->
- throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
- _ ->
- validate_binary_list(client_preferred_next_protocols, PreferredProtocols),
- validate_npn_ordering(Precedence),
- Value
- end;
-
-validate_option(client_preferred_next_protocols, undefined) ->
- undefined;
-validate_option(next_protocols_advertised = Opt, Value) when is_list(Value) ->
- case ssl_record:highest_protocol_version([]) of
- {3,0} ->
- throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
- _ ->
- validate_binary_list(next_protocols_advertised, Value),
- Value
- end;
-
-validate_option(next_protocols_advertised, undefined) ->
- undefined;
-validate_option(Opt, Value) ->
- throw({error, {options, {Opt, Value}}}).
-
-validate_npn_ordering(client) ->
- ok;
-validate_npn_ordering(server) ->
- ok;
-validate_npn_ordering(Value) ->
- throw({error, {options, {client_preferred_next_protocols, {invalid_precedence, Value}}}}).
-
-validate_binary_list(Opt, List) ->
- lists:foreach(
- fun(Bin) when is_binary(Bin),
- byte_size(Bin) > 0,
- byte_size(Bin) < 256 ->
- ok;
- (Bin) ->
- throw({error, {options, {Opt, {invalid_protocol, Bin}}}})
- end, List).
-
-validate_versions([], Versions) ->
- Versions;
-validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
- Version == 'tlsv1.1';
- Version == tlsv1;
- Version == sslv3 ->
- validate_versions(Rest, Versions);
-validate_versions([Ver| _], Versions) ->
- throw({error, {options, {Ver, {versions, Versions}}}}).
-
-validate_inet_option(mode, Value)
- when Value =/= list, Value =/= binary ->
- throw({error, {options, {mode,Value}}});
-validate_inet_option(packet, Value)
- when not (is_atom(Value) orelse is_integer(Value)) ->
- throw({error, {options, {packet,Value}}});
-validate_inet_option(packet_size, Value)
- when not is_integer(Value) ->
- throw({error, {options, {packet_size,Value}}});
-validate_inet_option(header, Value)
- when not is_integer(Value) ->
- throw({error, {options, {header,Value}}});
-validate_inet_option(active, Value)
- when Value =/= true, Value =/= false, Value =/= once ->
- throw({error, {options, {active,Value}}});
-validate_inet_option(_, _) ->
- ok.
-
-%% The option cacerts overrides cacertsfile
-ca_cert_default(_,_, [_|_]) ->
- undefined;
-ca_cert_default(verify_none, _, _) ->
- undefined;
-ca_cert_default(verify_peer, {Fun,_}, _) when is_function(Fun) ->
- undefined;
-%% Server that wants to verify_peer and has no verify_fun must have
-%% some trusted certs.
-ca_cert_default(verify_peer, undefined, _) ->
- "".
-
-emulated_options() ->
- [mode, packet, active, header, packet_size].
-
-internal_inet_values() ->
- [{packet_size,0},{packet, 0},{header, 0},{active, false},{mode,binary}].
-
-socket_options(InetValues) ->
- #socket_options{
- mode = proplists:get_value(mode, InetValues, lists),
- header = proplists:get_value(header, InetValues, 0),
- active = proplists:get_value(active, InetValues, active),
- packet = proplists:get_value(packet, InetValues, 0),
- packet_size = proplists:get_value(packet_size, InetValues)
- }.
-
-emulated_options(Opts) ->
- emulated_options(Opts, internal_inet_values(), #socket_options{}).
-
-emulated_options([{mode,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(mode,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{mode=Opt});
-emulated_options([{header,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(header,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{header=Opt});
-emulated_options([{active,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(active,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{active=Opt});
-emulated_options([{packet,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(packet,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{packet=Opt});
-emulated_options([{packet_size,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(packet_size,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{packet_size=Opt});
-emulated_options([Opt|Opts], Inet, Emulated) ->
- emulated_options(Opts, [Opt|Inet], Emulated);
-emulated_options([], Inet,Emulated) ->
- {Inet, Emulated}.
-
-cipher_suites(Version, []) ->
- ssl_cipher:filter_suites(ssl_cipher:suites(Version));
-cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
- Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
- ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
-cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
- Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
- ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
-cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported0 = ssl_cipher:suites(Version)
- ++ ssl_cipher:anonymous_suites()
- ++ ssl_cipher:psk_suites(Version)
- ++ ssl_cipher:srp_suites(),
- Supported1 = ssl_cipher:filter_suites(Supported0),
- case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported1)] of
- [] ->
- Supported1;
- Ciphers ->
- Ciphers
- end;
-cipher_suites(Version, [Head | _] = Ciphers0) when is_list(Head) ->
- %% Format: ["RC4-SHA","RC4-MD5"]
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- Ciphers0],
- cipher_suites(Version, Ciphers);
-cipher_suites(Version, Ciphers0) ->
- %% Format: "RC4-SHA:RC4-MD5"
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- string:tokens(Ciphers0, ":")],
- cipher_suites(Version, Ciphers).
-
-unexpected_format(Error) ->
- lists:flatten(io_lib:format("Unexpected error: ~p", [Error])).
-
-file_error_format({error, Error})->
- case file:format_error(Error) of
- "unknown POSIX error" ->
- "decoding error";
- Str ->
- Str
- end;
-file_error_format(_) ->
- "decoding error".
-
-file_desc(cacertfile) ->
- "Invalid CA certificate file ";
-file_desc(certfile) ->
- "Invalid certificate file ";
-file_desc(keyfile) ->
- "Invalid key file ";
-file_desc(dhfile) ->
- "Invalid DH params file ".
-
-detect(_Pred, []) ->
- undefined;
-detect(Pred, [H|T]) ->
- case Pred(H) of
- true ->
- H;
- _ ->
- detect(Pred, T)
- end.
-
-make_next_protocol_selector(undefined) ->
- undefined;
-make_next_protocol_selector({client, AllProtocols, DefaultProtocol}) ->
- fun(AdvertisedProtocols) ->
- case detect(fun(PreferredProtocol) ->
- lists:member(PreferredProtocol, AdvertisedProtocols)
- end, AllProtocols) of
- undefined ->
- DefaultProtocol;
- PreferredProtocol ->
- PreferredProtocol
- end
- end;
+ tls:random_bytes(N).
-make_next_protocol_selector({server, AllProtocols, DefaultProtocol}) ->
- fun(AdvertisedProtocols) ->
- case detect(fun(PreferredProtocol) ->
- lists:member(PreferredProtocol, AllProtocols)
- end,
- AdvertisedProtocols) of
- undefined ->
- DefaultProtocol;
- PreferredProtocol ->
- PreferredProtocol
- end
- end.
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 9e1c3a09bf..b186a1015a 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -240,7 +240,7 @@ find_issuer(OtpCert, CertDbHandle) ->
Acc
end,
- try ssl_certificate_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
+ try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
issuer_not_found ->
{error, issuer_not_found}
catch
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index dc413d6dfc..898b421dff 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -1024,30 +1024,32 @@ filter(DerCert, Ciphers) ->
%% Description: filter suites for algorithms
%%-------------------------------------------------------------------
filter_suites(Suites = [{_,_,_}|_]) ->
- Algos = crypto:algorithms(),
+ Algos = crypto:supports(),
lists:filter(fun({KeyExchange, Cipher, Hash}) ->
- is_acceptable_keyexchange(KeyExchange, Algos) andalso
- is_acceptable_cipher(Cipher, Algos) andalso
- is_acceptable_hash(Hash, Algos)
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, proplists:get_value(hashs, Algos))
end, Suites);
filter_suites(Suites = [{_,_,_,_}|_]) ->
- Algos = crypto:algorithms(),
+ Algos = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Algos),
lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) ->
- is_acceptable_keyexchange(KeyExchange, Algos) andalso
- is_acceptable_cipher(Cipher, Algos) andalso
- is_acceptable_hash(Hash, Algos) andalso
- is_acceptable_prf(Prf, Algos)
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, Hashs) andalso
+ is_acceptable_prf(Prf, Hashs)
end, Suites);
filter_suites(Suites) ->
- Algos = crypto:algorithms(),
+ Algos = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Algos),
lists:filter(fun(Suite) ->
{KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite),
- is_acceptable_keyexchange(KeyExchange, Algos) andalso
- is_acceptable_cipher(Cipher, Algos) andalso
- is_acceptable_hash(Hash, Algos) andalso
- is_acceptable_prf(Prf, Algos)
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, Hashs) andalso
+ is_acceptable_prf(Prf, Hashs)
end, Suites).
is_acceptable_keyexchange(KeyExchange, Algos)
@@ -1056,7 +1058,7 @@ is_acceptable_keyexchange(KeyExchange, Algos)
KeyExchange == ecdh_rsa;
KeyExchange == ecdhe_rsa;
KeyExchange == ecdh_anon ->
- proplists:get_bool(ec, Algos);
+ proplists:get_bool(ecdh, Algos);
is_acceptable_keyexchange(_, _) ->
true.
diff --git a/lib/ssl/src/ssl_connection_sup.erl b/lib/ssl/src/ssl_connection_sup.erl
index 78cfda5e63..fb1c6e11a6 100644
--- a/lib/ssl/src/ssl_connection_sup.erl
+++ b/lib/ssl/src/ssl_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -56,10 +56,10 @@ init(_O) ->
MaxT = 3600,
Name = undefined, % As simple_one_for_one is used.
- StartFunc = {ssl_connection, start_link, []},
+ StartFunc = {tls_connection, start_link, []},
Restart = temporary, % E.g. should not be restarted
Shutdown = 4000,
- Modules = [ssl_connection],
+ Modules = [tls_connection],
Type = worker,
ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index b2387a0ee7..eb1a1dbf62 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -20,7 +20,7 @@
%%
%%----------------------------------------------------------------------
%% Purpose: Record and constant defenitions for the SSL-handshake protocol
-%% see RFC 4346
+%% see RFC 5246. Also includes supported hello extensions.
%%----------------------------------------------------------------------
-ifndef(ssl_handshake).
@@ -91,21 +91,10 @@
% -define(NULL, 0). %% Already defined by ssl_internal.hrl
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% Hello messages - RFC 4346 section 7.4.2
+%%% Hello messages - RFC 5246 section 7.4.1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--record(client_hello, {
- client_version,
- random,
- session_id, % opaque SessionID<0..32>
- cipher_suites, % cipher_suites<2..2^16-1>
- compression_methods, % compression_methods<1..2^8-1>,
- renegotiation_info,
- srp, % srp username to send
- hash_signs, % supported combinations of hashes/signature algos
- ec_point_formats, % supported ec point formats
- elliptic_curves, % supported elliptic curver
- next_protocol_negotiation = undefined % [binary()]
- }).
+
+%% client_hello defined in tls_handshake.hrl and dtls_handshake.hrl
-record(server_hello, {
server_version,
@@ -121,7 +110,7 @@
}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% Server authentication and key exchange messages - RFC 4346 section 7.4.3
+%%% Server authentication and key exchange messages - RFC 5246 section 7.4.3
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% opaque ASN.1Cert<2^24-1>;
@@ -193,7 +182,7 @@
-record(server_hello_done, {}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% Certificate request - RFC 4346 section 7.4.4
+%%% Certificate request - RFC 5246 section 7.4.4
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% enum {
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index caea528a08..1b06e351cf 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -104,7 +104,8 @@ connection_init(Trustedcerts, Role) ->
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
MD5 = crypto:hash(md5, File),
- case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of
+ MD5 = crypto:md5(File),
+ case ssl_pkix_db:lookup_cached_pem(DbHandle, MD5) of
[{Content,_}] ->
{ok, Content};
[Content] ->
@@ -132,7 +133,7 @@ clear_pem_cache() ->
%% serialnumber(), issuer()}.
%% --------------------------------------------------------------------
lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
- ssl_certificate_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer).
+ ssl_pkix_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer).
%%--------------------------------------------------------------------
-spec new_session_id(integer()) -> session_id().
@@ -194,7 +195,7 @@ init([Name, Opts]) ->
CacheCb = proplists:get_value(session_cb, Opts, ssl_session_cache),
SessionLifeTime =
proplists:get_value(session_lifetime, Opts, ?'24H_in_sec'),
- CertDb = ssl_certificate_db:create(),
+ CertDb = ssl_pkix_db:create(),
SessionCache = CacheCb:init(proplists:get_value(session_cb_init_args, Opts, [])),
Timer = erlang:send_after(SessionLifeTime * 1000 + 5000,
self(), validate_sessions),
@@ -227,7 +228,7 @@ handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From,
session_cache = Cache} = State) ->
Result =
try
- {ok, Ref} = ssl_certificate_db:add_trusted_certs(Pid, Trustedcerts, Db),
+ {ok, Ref} = ssl_pkix_db:add_trusted_certs(Pid, Trustedcerts, Db),
{ok, Ref, CertDb, FileRefDb, PemChace, Cache}
catch
_:Reason ->
@@ -244,7 +245,7 @@ handle_call({{new_session_id,Port}, _},
handle_call({{cache_pem, File}, _Pid}, _,
#state{certificate_db = Db} = State) ->
- try ssl_certificate_db:cache_pem_file(File, Db) of
+ try ssl_pkix_db:cache_pem_file(File, Db) of
Result ->
{reply, Result, State}
catch
@@ -252,7 +253,7 @@ handle_call({{cache_pem, File}, _Pid}, _,
{reply, {error, Reason}, State}
end;
handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_,PemChace]} = State) ->
- ssl_certificate_db:clear(PemChace),
+ ssl_pkix_db:clear(PemChace),
{reply, ok, State}.
%%--------------------------------------------------------------------
@@ -315,11 +316,11 @@ handle_info({delayed_clean_session, Key}, #state{session_cache = Cache,
{noreply, State};
handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) ->
- case ssl_certificate_db:db_size(PemChace) of
+ case ssl_pkix_db:db_size(PemChace) of
N when N < ?NOT_TO_BIG ->
ok;
_ ->
- ssl_certificate_db:clear(PemChace)
+ ssl_pkix_db:clear(PemChace)
end,
erlang:send_after(?CLEAR_PEM_CACHE, self(), clear_pem_cache),
{noreply, State};
@@ -328,7 +329,7 @@ handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) ->
handle_info({clean_cert_db, Ref, File},
#state{certificate_db = [CertDb,RefDb, PemCache]} = State) ->
- case ssl_certificate_db:lookup(Ref, RefDb) of
+ case ssl_pkix_db:lookup(Ref, RefDb) of
undefined -> %% Alredy cleaned
ok;
_ ->
@@ -357,7 +358,7 @@ terminate(_Reason, #state{certificate_db = Db,
session_cache_cb = CacheCb,
session_validation_timer = Timer}) ->
erlang:cancel_timer(Timer),
- ssl_certificate_db:remove(Db),
+ ssl_pkix_db:remove(Db),
CacheCb:terminate(SessionCache),
ok.
@@ -466,17 +467,17 @@ new_id(Port, Tries, Cache, CacheCb) ->
end.
clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->
- case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
+ case ssl_pkix_db:ref_count(Ref, RefDb, 0) of
0 ->
MD5 = crypto:hash(md5, File),
- case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of
+ case ssl_pkix_db:lookup_cached_pem(PemCache, MD5) of
[{Content, Ref}] ->
- ssl_certificate_db:insert(MD5, Content, PemCache);
+ ssl_pkix_db:insert(MD5, Content, PemCache);
_ ->
ok
end,
- ssl_certificate_db:remove(Ref, RefDb),
- ssl_certificate_db:remove_trusted_certs(Ref, CertDb);
+ ssl_pkix_db:remove(Ref, RefDb),
+ ssl_pkix_db:remove_trusted_certs(Ref, CertDb);
_ ->
ok
end.
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_pkix_db.erl
index cdff73336e..9de50c8f26 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_pkix_db.erl
@@ -21,7 +21,7 @@
%% Purpose: Storage for trusted certificates
%%----------------------------------------------------------------------
--module(ssl_certificate_db).
+-module(ssl_pkix_db).
-include("ssl_internal.hrl").
-include_lib("public_key/include/public_key.hrl").
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index f73da92a52..2fd17f9c35 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -143,34 +143,6 @@
-define(LOWEST_MAJOR_SUPPORTED_VERSION, 3).
--record(ssl_tls, { %% From inet driver
- port,
- type,
- version,
- fragment
- }).
-
-%% -record(tls_plain_text, {
-%% type,
-%% version, % #protocol_version{}
-%% length, % unit 16
-%% fragment % opaque
-%% }).
-
-%% -record(tls_compressed, {
-%% type,
-%% version,
-%% length, % unit 16
-%% fragment % opaque
-%% }).
-
-%% -record(tls_cipher_text, {
-%% type,
-%% version,
-%% length,
-%% cipher,
-%% fragment
-%% }).
-record(generic_stream_cipher, {
content, % opaque content[TLSCompressed.length];
diff --git a/lib/ssl/src/ssl_srp_primes.hrl b/lib/ssl/src/ssl_srp_primes.hrl
deleted file mode 100644
index 4bd534efbf..0000000000
--- a/lib/ssl/src/ssl_srp_primes.hrl
+++ /dev/null
@@ -1 +0,0 @@
--type srp_parameters() :: srp_1024 | srp_1536 | srp_2048 | srp_3072 | srp_4096 | srp_6144 | srp_8192.
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index f8fd9efd07..8ab66d0627 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -184,6 +184,22 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
-spec suites(1|2|3) -> [cipher_suite()].
suites(Minor) when Minor == 1; Minor == 2->
+ case sufficent_ec_support() of
+ true ->
+ all_suites(Minor);
+ false ->
+ no_ec_suites(Minor)
+ end;
+
+suites(Minor) when Minor == 3 ->
+ case sufficent_ec_support() of
+ true ->
+ all_suites(3) ++ all_suites(2);
+ false ->
+ no_ec_suites(3) ++ no_ec_suites(2)
+ end.
+
+all_suites(Minor) when Minor == 1; Minor == 2->
[
?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
@@ -208,7 +224,7 @@ suites(Minor) when Minor == 1; Minor == 2->
?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
?TLS_RSA_WITH_AES_128_CBC_SHA,
- %%?TLS_RSA_WITH_IDEA_CBC_SHA,
+
?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_SHA,
@@ -216,31 +232,55 @@ suites(Minor) when Minor == 1; Minor == 2->
?TLS_DHE_RSA_WITH_DES_CBC_SHA,
?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDH_RSA_WITH_RC4_128_SHA,
+
?TLS_RSA_WITH_DES_CBC_SHA
- ];
-
-suites(Minor) when Minor == 3 ->
+ ];
+all_suites(3) ->
[
?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
-
+
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_256_CBC_SHA256,
-
+
?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA256
+ ].
+no_ec_suites(Minor) when Minor == 1; Minor == 2->
+ [
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_WITH_RC4_128_SHA,
+ ?TLS_RSA_WITH_RC4_128_MD5,
+ ?TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ ?TLS_RSA_WITH_DES_CBC_SHA
+ ];
+no_ec_suites(3) ->
+ [
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+ ?TLS_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
?TLS_RSA_WITH_AES_128_CBC_SHA256
- %% ?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- %% ?TLS_DH_anon_WITH_AES_256_CBC_SHA256
- ] ++ suites(2).
+ ].
%%--------------------------------------------------------------------
%%% Internal functions
@@ -386,3 +426,7 @@ enum_to_oid(22) -> ?secp256k1;
enum_to_oid(23) -> ?secp256r1;
enum_to_oid(24) -> ?secp384r1;
enum_to_oid(25) -> ?secp521r1.
+
+sufficent_ec_support() ->
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)).
diff --git a/lib/ssl/src/tls.erl b/lib/ssl/src/tls.erl
new file mode 100644
index 0000000000..fcecf8196f
--- /dev/null
+++ b/lib/ssl/src/tls.erl
@@ -0,0 +1,1037 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+%%% Purpose : Main API module for SSL.
+
+-module(tls).
+
+-export([start/0, start/1, stop/0, transport_accept/1,
+ transport_accept/2, ssl_accept/1, ssl_accept/2, ssl_accept/3,
+ cipher_suites/0, cipher_suites/1, suite_definition/1,
+ close/1, shutdown/2,
+ connect/3, connect/2, connect/4, connection_info/1,
+ controlling_process/2, listen/2, peername/1, peercert/1,
+ recv/2, recv/3, send/2, getopts/2, setopts/2, sockname/1,
+ versions/0, session_info/1, format_error/1,
+ renegotiate/1, prf/5, clear_pem_cache/0, random_bytes/1, negotiated_next_protocol/1]).
+
+-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").
+
+%% Visible in API
+-export_type([connect_option/0, listen_option/0, ssl_option/0, transport_option/0,
+ erl_cipher_suite/0, %% From ssl_cipher.hrl
+ tls_atom_version/0, %% From ssl_internal.hrl
+ prf_random/0, sslsocket/0]).
+
+-record(config, {ssl, %% SSL parameters
+ inet_user, %% User set inet options
+ emulated, %% #socket_option{} emulated
+ inet_ssl, %% inet options for internal ssl socket
+ cb %% Callback info
+ }).
+
+-type sslsocket() :: #sslsocket{}.
+-type connect_option() :: socket_connect_option() | ssl_option() | transport_option().
+-type socket_connect_option() :: gen_tcp:connect_option().
+-type listen_option() :: socket_listen_option() | ssl_option() | transport_option().
+-type socket_listen_option() :: gen_tcp:listen_option().
+
+-type ssl_option() :: {verify, verify_type()} |
+ {verify_fun, {fun(), InitialUserState::term()}} |
+ {fail_if_no_peer_cert, boolean()} | {depth, integer()} |
+ {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
+ {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
+ {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
+ {user_lookup_fun, {fun(), InitialUserState::term()}} |
+ {psk_identity, string()} |
+ {srp_identity, {string(), string()}} |
+ {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
+ {reuse_session, fun()} | {hibernate_after, integer()|undefined} |
+ {next_protocols_advertised, list(binary())} |
+ {client_preferred_next_protocols, binary(), client | server, list(binary())}.
+
+-type verify_type() :: verify_none | verify_peer.
+-type path() :: string().
+-type ciphers() :: [erl_cipher_suite()] |
+ string(). % (according to old API)
+-type ssl_imp() :: new | old.
+
+-type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(),
+ ClosedTag::atom(), ErrTag::atom()}}.
+-type prf_random() :: client_random | server_random.
+
+%%--------------------------------------------------------------------
+-spec start() -> ok | {error, reason()}.
+-spec start(permanent | transient | temporary) -> ok | {error, reason()}.
+%%
+%% Description: Utility function that starts the ssl,
+%% crypto and public_key applications. Default type
+%% is temporary. see application(3)
+%%--------------------------------------------------------------------
+start() ->
+ application:start(crypto),
+ application:start(public_key),
+ application:start(ssl).
+
+start(Type) ->
+ application:start(crypto, Type),
+ application:start(public_key, Type),
+ application:start(ssl, Type).
+
+%%--------------------------------------------------------------------
+-spec stop() -> ok.
+%%
+%% Description: Stops the ssl application.
+%%--------------------------------------------------------------------
+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.
+%%--------------------------------------------------------------------
+connect(Socket, SslOptions) when is_port(Socket) ->
+ connect(Socket, SslOptions, infinity).
+
+connect(Socket, SslOptions0, Timeout) when is_port(Socket) ->
+ {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0,
+ {gen_tcp, tcp, tcp_closed, tcp_error}),
+ EmulatedOptions = emulated_options(),
+ {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
+ try handle_options(SslOptions0 ++ SocketValues, client) of
+ {ok, #config{cb = CbInfo, ssl = SslOptions, emulated = EmOpts}} ->
+
+ ok = ssl_socket:setopts(Transport, Socket, internal_inet_values()),
+ case ssl_socket:peername(Transport, Socket) of
+ {ok, {Address, Port}} ->
+ tls_connection:connect(Address, Port, Socket,
+ {SslOptions, EmOpts},
+ self(), CbInfo, Timeout);
+ {error, Error} ->
+ {error, Error}
+ end
+ catch
+ _:{error, Reason} ->
+ {error, Reason}
+ end;
+
+connect(Host, Port, Options) ->
+ connect(Host, Port, Options, infinity).
+
+connect(Host, Port, Options, Timeout) ->
+ try handle_options(Options, client) of
+ {ok, Config} ->
+ do_connect(Host,Port,Config,Timeout)
+ catch
+ throw:Error ->
+ Error
+ end.
+
+%%--------------------------------------------------------------------
+-spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
+
+%%
+%% Description: Creates an ssl listen socket.
+%%--------------------------------------------------------------------
+listen(_Port, []) ->
+ {error, nooptions};
+listen(Port, Options0) ->
+ try
+ {ok, Config} = handle_options(Options0, server),
+ #config{cb = {Transport, _, _, _}, inet_user = Options} = Config,
+ case Transport:listen(Port, Options) of
+ {ok, ListenSocket} ->
+ {ok, #sslsocket{pid = {ListenSocket, Config}}};
+ Err = {error, _} ->
+ Err
+ end
+ catch
+ Error = {error, _} ->
+ 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
+%%--------------------------------------------------------------------
+transport_accept(ListenSocket) ->
+ transport_accept(ListenSocket, infinity).
+
+transport_accept(#sslsocket{pid = {ListenSocket, #config{cb = CbInfo, ssl = SslOpts}}}, Timeout) ->
+
+ %% The setopt could have been invoked on the listen socket
+ %% and options should be inherited.
+ EmOptions = emulated_options(),
+ {Transport,_,_, _} = CbInfo,
+ {ok, SocketValues} = ssl_socket:getopts(Transport, ListenSocket, EmOptions),
+ ok = ssl_socket:setopts(Transport, ListenSocket, internal_inet_values()),
+ case Transport:accept(ListenSocket, Timeout) of
+ {ok, Socket} ->
+ ok = ssl_socket:setopts(Transport, ListenSocket, SocketValues),
+ {ok, Port} = ssl_socket:port(Transport, Socket),
+ ConnArgs = [server, "localhost", Port, Socket,
+ {SslOpts, socket_options(SocketValues)}, self(), CbInfo],
+ case ssl_connection_sup:start_child(ConnArgs) of
+ {ok, Pid} ->
+ tls_connection:socket_control(Socket, Pid, Transport);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ 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(port(), [ssl_option()| transport_option()], timeout()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
+%%
+%% Description: Performs accept on an ssl listen socket. e.i. performs
+%% ssl handshake.
+%%--------------------------------------------------------------------
+ssl_accept(ListenSocket) ->
+ ssl_accept(ListenSocket, infinity).
+
+ssl_accept(#sslsocket{} = Socket, Timeout) ->
+ tls_connection:handshake(Socket, Timeout);
+
+ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
+ ssl_accept(ListenSocket, SslOptions, infinity).
+
+ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
+ {Transport,_,_,_} =
+ proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
+ EmulatedOptions = emulated_options(),
+ {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
+ try handle_options(SslOptions ++ SocketValues, server) of
+ {ok, #config{cb = CbInfo, ssl = SslOpts, emulated = EmOpts}} ->
+ ok = ssl_socket:setopts(Transport, Socket, internal_inet_values()),
+ {ok, Port} = ssl_socket:port(Transport, Socket),
+ tls_connection:ssl_accept(Port, Socket,
+ {SslOpts, EmOpts},
+ self(), CbInfo, Timeout)
+ catch
+ Error = {error, _Reason} -> Error
+ end.
+
+%%--------------------------------------------------------------------
+-spec close(#sslsocket{}) -> term().
+%%
+%% Description: Close an ssl connection
+%%--------------------------------------------------------------------
+close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ tls_connection:close(Pid);
+close(#sslsocket{pid = {ListenSocket, #config{cb={Transport,_, _, _}}}}) ->
+ Transport:close(ListenSocket).
+
+%%--------------------------------------------------------------------
+-spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}.
+%%
+%% Description: Sends data over the ssl connection
+%%--------------------------------------------------------------------
+send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
+ tls_connection:send(Pid, Data);
+send(#sslsocket{pid = {ListenSocket, #config{cb={Transport, _, _, _}}}}, Data) ->
+ 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
+%%--------------------------------------------------------------------
+recv(Socket, Length) ->
+ recv(Socket, Length, infinity).
+recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid) ->
+ tls_connection:recv(Pid, Length, Timeout);
+recv(#sslsocket{pid = {Listen,
+ #config{cb={Transport, _, _, _}}}}, _,_) when is_port(Listen)->
+ Transport:recv(Listen, 0). %% {error,enotconn}
+
+%%--------------------------------------------------------------------
+-spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
+%%
+%% 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) ->
+ tls_connection:new_user(Pid, NewOwner);
+controlling_process(#sslsocket{pid = {Listen,
+ #config{cb={Transport, _, _, _}}}},
+ NewOwner) when is_port(Listen),
+ is_pid(NewOwner) ->
+ Transport:controlling_process(Listen, NewOwner).
+
+%%--------------------------------------------------------------------
+-spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
+ {error, reason()}.
+%%
+%% Description: Returns ssl protocol and cipher used for the connection
+%%--------------------------------------------------------------------
+connection_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ tls_connection:info(Pid);
+connection_info(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
+ {error, enotconn}.
+
+%%--------------------------------------------------------------------
+-spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
+%%
+%% Description: same as inet:peername/1.
+%%--------------------------------------------------------------------
+peername(#sslsocket{pid = Pid, fd = {Transport, Socket}}) when is_pid(Pid)->
+ ssl_socket:peername(Transport, Socket);
+peername(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}}) ->
+ ssl_socket:peername(Transport, ListenSocket). %% Will return {error, enotconn}
+
+%%--------------------------------------------------------------------
+-spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
+%%
+%% Description: Returns the peercert.
+%%--------------------------------------------------------------------
+peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ case tls_connection:peer_certificate(Pid) of
+ {ok, undefined} ->
+ {error, no_peercert};
+ Result ->
+ Result
+ end;
+peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
+ {error, enotconn}.
+
+%%--------------------------------------------------------------------
+-spec suite_definition(cipher_suite()) -> erl_cipher_suite().
+%%
+%% Description: Return erlang cipher suite definition.
+%%--------------------------------------------------------------------
+suite_definition(S) ->
+ {KeyExchange, Cipher, Hash, _} = ssl_cipher:suite_definition(S),
+ {KeyExchange, Cipher, Hash}.
+
+%%--------------------------------------------------------------------
+-spec negotiated_next_protocol(#sslsocket{}) -> {ok, binary()} | {error, reason()}.
+%%
+%% Description: Returns the next protocol that has been negotiated. If no
+%% protocol has been negotiated will return {error, next_protocol_not_negotiated}
+%%--------------------------------------------------------------------
+negotiated_next_protocol(#sslsocket{pid = Pid}) ->
+ tls_connection:negotiated_next_protocol(Pid).
+
+-spec cipher_suites() -> [erl_cipher_suite()].
+-spec cipher_suites(erlang | openssl | all) -> [erl_cipher_suite()] | [string()].
+
+%% Description: Returns all supported cipher suites.
+%%--------------------------------------------------------------------
+cipher_suites() ->
+ cipher_suites(erlang).
+
+cipher_suites(erlang) ->
+ Version = tls_record:highest_protocol_version([]),
+ [suite_definition(S) || S <- ssl_cipher:suites(Version)];
+
+cipher_suites(openssl) ->
+ Version = tls_record:highest_protocol_version([]),
+ [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)];
+cipher_suites(all) ->
+ Version = tls_record:highest_protocol_version([]),
+ Supported = ssl_cipher:suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites(),
+ [suite_definition(S) || S <- Supported].
+
+%%--------------------------------------------------------------------
+-spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
+ {ok, [gen_tcp:option()]} | {error, reason()}.
+%%
+%% Description: Gets options
+%%--------------------------------------------------------------------
+getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
+ tls_connection:get_opts(Pid, OptionTags);
+getopts(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}},
+ OptionTags) when is_list(OptionTags) ->
+ try ssl_socket:getopts(Transport, ListenSocket, OptionTags) of
+ {ok, _} = Result ->
+ Result;
+ {error, InetError} ->
+ {error, {options, {socket_options, OptionTags, InetError}}}
+ catch
+ _:_ ->
+ {error, {options, {socket_options, OptionTags}}}
+ end;
+getopts(#sslsocket{}, OptionTags) ->
+ {error, {options, {socket_options, OptionTags}}}.
+
+%%--------------------------------------------------------------------
+-spec setopts(#sslsocket{}, [gen_tcp:option()]) -> ok | {error, reason()}.
+%%
+%% Description: Sets options
+%%--------------------------------------------------------------------
+setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
+ try proplists:expand([{binary, [{mode, binary}]},
+ {list, [{mode, list}]}], Options0) of
+ Options ->
+ tls_connection:set_opts(Pid, Options)
+ catch
+ _:_ ->
+ {error, {options, {not_a_proplist, Options0}}}
+ end;
+
+setopts(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}}, Options) when is_list(Options) ->
+ try ssl_socket:setopts(Transport, ListenSocket, Options) of
+ ok ->
+ ok;
+ {error, InetError} ->
+ {error, {options, {socket_options, Options, InetError}}}
+ catch
+ _:Error ->
+ {error, {options, {socket_options, Options, Error}}}
+ end;
+setopts(#sslsocket{}, Options) ->
+ {error, {options,{not_a_proplist, Options}}}.
+
+%%---------------------------------------------------------------
+-spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
+%%
+%% Description: Same as gen_tcp:shutdown/2
+%%--------------------------------------------------------------------
+shutdown(#sslsocket{pid = {Listen, #config{cb={Transport,_, _, _}}}},
+ How) when is_port(Listen) ->
+ Transport:shutdown(Listen, How);
+shutdown(#sslsocket{pid = Pid}, How) ->
+ tls_connection:shutdown(Pid, How).
+
+%%--------------------------------------------------------------------
+-spec sockname(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
+%%
+%% Description: Same as inet:sockname/1
+%%--------------------------------------------------------------------
+sockname(#sslsocket{pid = {Listen, #config{cb={Transport,_, _, _}}}}) when is_port(Listen) ->
+ ssl_socket:sockname(Transport, Listen);
+
+sockname(#sslsocket{pid = Pid, fd = {Transport, Socket}}) when is_pid(Pid) ->
+ ssl_socket:sockname(Transport, Socket).
+
+%%---------------------------------------------------------------
+-spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
+%%
+%% Description: Returns list of session info currently [{session_id, session_id(),
+%% {cipher_suite, cipher_suite()}]
+%%--------------------------------------------------------------------
+session_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ tls_connection:session_info(Pid);
+session_info(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
+ {error, enotconn}.
+
+%%---------------------------------------------------------------
+-spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} |
+ {available, [tls_atom_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_SUPPORTED_VERSIONS,
+ [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}].
+
+
+%%---------------------------------------------------------------
+-spec renegotiate(#sslsocket{}) -> ok | {error, reason()}.
+%%
+%% Description: Initiates a renegotiation.
+%%--------------------------------------------------------------------
+renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ tls_connection:renegotiation(Pid);
+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()}.
+%%
+%% Description: use a ssl sessions TLS PRF to generate key material
+%%--------------------------------------------------------------------
+prf(#sslsocket{pid = Pid},
+ Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
+ tls_connection:prf(Pid, Secret, Label, Seed, WantedLength);
+prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
+ {error, enotconn}.
+
+%%--------------------------------------------------------------------
+-spec clear_pem_cache() -> ok.
+%%
+%% Description: Clear the PEM cache
+%%--------------------------------------------------------------------
+clear_pem_cache() ->
+ ssl_manager:clear_pem_cache().
+
+%%---------------------------------------------------------------
+-spec format_error({error, term()}) -> list().
+%%
+%% Description: Creates error string.
+%%--------------------------------------------------------------------
+format_error({error, Reason}) ->
+ format_error(Reason);
+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({options,{FileType, File, Reason}}) when FileType == cacertfile;
+ FileType == certfile;
+ FileType == keyfile;
+ FileType == dhfile ->
+ Error = file_error_format(Reason),
+ file_desc(FileType) ++ File ++ ": " ++ Error;
+format_error({options, {socket_options, Option, Error}}) ->
+ lists:flatten(io_lib:format("Invalid transport socket option ~p: ~s", [Option, format_error(Error)]));
+format_error({options, {socket_options, Option}}) ->
+ lists:flatten(io_lib:format("Invalid socket option: ~p", [Option]));
+format_error({options, Options}) ->
+ lists:flatten(io_lib:format("Invalid TLS option: ~p", [Options]));
+
+format_error(Error) ->
+ case inet:format_error(Error) of
+ "unknown POSIX" ++ _ ->
+ unexpected_format(Error);
+ Other ->
+ Other
+ end.
+
+%%--------------------------------------------------------------------
+-spec random_bytes(integer()) -> binary().
+
+%%
+%% Description: Generates cryptographically secure random sequence if possible
+%% fallbacks on pseudo random function
+%%--------------------------------------------------------------------
+random_bytes(N) ->
+ try crypto:strong_rand_bytes(N) of
+ RandBytes ->
+ RandBytes
+ catch
+ error:low_entropy ->
+ crypto:rand_bytes(N)
+ end.
+
+%%%--------------------------------------------------------------
+%%% Internal functions
+%%%--------------------------------------------------------------------
+do_connect(Address, Port,
+ #config{cb=CbInfo, inet_user=UserOpts, ssl=SslOpts,
+ emulated=EmOpts,inet_ssl=SocketOpts},
+ Timeout) ->
+ {Transport, _, _, _} = CbInfo,
+ try Transport:connect(Address, Port, SocketOpts, Timeout) of
+ {ok, Socket} ->
+ tls_connection:connect(Address, Port, Socket, {SslOpts,EmOpts},
+ self(), CbInfo, Timeout);
+ {error, Reason} ->
+ {error, Reason}
+ catch
+ exit:{function_clause, _} ->
+ {error, {options, {cb_info, CbInfo}}};
+ exit:badarg ->
+ {error, {options, {socket_options, UserOpts}}};
+ exit:{badarg, _} ->
+ {error, {options, {socket_options, UserOpts}}}
+ end.
+
+handle_options(Opts0, _Role) ->
+ Opts = proplists:expand([{binary, [{mode, binary}]},
+ {list, [{mode, list}]}], Opts0),
+ ReuseSessionFun = fun(_, _, _, _) -> true end,
+
+ DefaultVerifyNoneFun =
+ {fun(_,{bad_cert, _}, UserState) ->
+ {valid, UserState};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, []},
+
+ VerifyNoneFun = handle_option(verify_fun, Opts, DefaultVerifyNoneFun),
+
+ UserFailIfNoPeerCert = handle_option(fail_if_no_peer_cert, Opts, false),
+ UserVerifyFun = handle_option(verify_fun, Opts, undefined),
+ CaCerts = handle_option(cacerts, Opts, undefined),
+
+ {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun} =
+ %% Handle 0, 1, 2 for backwards compatibility
+ case proplists:get_value(verify, Opts, verify_none) of
+ 0 ->
+ {verify_none, false,
+ ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
+ 1 ->
+ {verify_peer, false,
+ ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
+ 2 ->
+ {verify_peer, true,
+ ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
+ verify_none ->
+ {verify_none, false,
+ ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
+ verify_peer ->
+ {verify_peer, UserFailIfNoPeerCert,
+ ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
+ Value ->
+ throw({error, {options, {verify, Value}}})
+ end,
+
+ CertFile = handle_option(certfile, Opts, <<>>),
+
+ Versions = case handle_option(versions, Opts, []) of
+ [] ->
+ tls_record:supported_protocol_versions();
+ Vsns ->
+ [tls_record:protocol_version(Vsn) || Vsn <- Vsns]
+ end,
+
+ SSLOptions = #ssl_options{
+ versions = Versions,
+ verify = validate_option(verify, Verify),
+ verify_fun = VerifyFun,
+ fail_if_no_peer_cert = FailIfNoPeerCert,
+ verify_client_once = handle_option(verify_client_once, Opts, false),
+ depth = handle_option(depth, Opts, 1),
+ cert = handle_option(cert, Opts, undefined),
+ certfile = CertFile,
+ key = handle_option(key, Opts, undefined),
+ keyfile = handle_option(keyfile, Opts, CertFile),
+ password = handle_option(password, Opts, ""),
+ cacerts = CaCerts,
+ cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
+ dh = handle_option(dh, Opts, undefined),
+ dhfile = handle_option(dhfile, Opts, undefined),
+ user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
+ psk_identity = handle_option(psk_identity, Opts, undefined),
+ srp_identity = handle_option(srp_identity, Opts, undefined),
+ ciphers = handle_option(ciphers, Opts, []),
+ %% 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),
+ renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT),
+ hibernate_after = handle_option(hibernate_after, Opts, undefined),
+ erl_dist = handle_option(erl_dist, Opts, false),
+ next_protocols_advertised =
+ handle_option(next_protocols_advertised, Opts, undefined),
+ next_protocol_selector =
+ make_next_protocol_selector(
+ handle_option(client_preferred_next_protocols, Opts, undefined))
+ },
+
+ CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
+ SslOptions = [versions, verify, verify_fun,
+ fail_if_no_peer_cert, verify_client_once,
+ depth, cert, certfile, key, keyfile,
+ password, cacerts, cacertfile, dh, dhfile,
+ user_lookup_fun, psk_identity, srp_identity, ciphers,
+ reuse_session, reuse_sessions, ssl_imp,
+ cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
+ erl_dist, next_protocols_advertised,
+ client_preferred_next_protocols],
+
+ SockOpts = lists:foldl(fun(Key, PropList) ->
+ proplists:delete(Key, PropList)
+ end, Opts, SslOptions),
+
+ {SSLsock, Emulated} = emulated_options(SockOpts),
+ {ok, #config{ssl=SSLOptions, emulated=Emulated, inet_ssl=SSLsock,
+ inet_user=SockOpts, cb=CbInfo}}.
+
+handle_option(OptionName, Opts, Default) ->
+ validate_option(OptionName,
+ proplists:get_value(OptionName, Opts, Default)).
+
+
+validate_option(versions, Versions) ->
+ validate_versions(Versions, Versions);
+validate_option(verify, Value)
+ when Value == verify_none; Value == verify_peer ->
+ Value;
+validate_option(verify_fun, undefined) ->
+ undefined;
+%% Backwards compatibility
+validate_option(verify_fun, Fun) when is_function(Fun) ->
+ {fun(_,{bad_cert, _} = Reason, OldFun) ->
+ case OldFun([Reason]) of
+ true ->
+ {valid, OldFun};
+ false ->
+ {fail, Reason}
+ end;
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, Fun};
+validate_option(verify_fun, {Fun, _} = Value) when is_function(Fun) ->
+ Value;
+validate_option(fail_if_no_peer_cert, Value)
+ when Value == true; Value == false ->
+ Value;
+validate_option(verify_client_once, Value)
+ when Value == true; Value == false ->
+ Value;
+validate_option(depth, Value) when is_integer(Value),
+ Value >= 0, Value =< 255->
+ Value;
+validate_option(cert, Value) when Value == undefined;
+ is_binary(Value) ->
+ Value;
+validate_option(certfile, undefined = Value) ->
+ Value;
+validate_option(certfile, Value) when is_binary(Value) ->
+ Value;
+validate_option(certfile, Value) when is_list(Value) ->
+ list_to_binary(Value);
+
+validate_option(key, undefined) ->
+ undefined;
+validate_option(key, {KeyType, Value}) when is_binary(Value),
+ KeyType == rsa; %% Backwards compatibility
+ KeyType == dsa; %% Backwards compatibility
+ KeyType == 'RSAPrivateKey';
+ KeyType == 'DSAPrivateKey';
+ KeyType == 'PrivateKeyInfo' ->
+ {KeyType, Value};
+
+validate_option(keyfile, undefined) ->
+ <<>>;
+validate_option(keyfile, Value) when is_binary(Value) ->
+ Value;
+validate_option(keyfile, Value) when is_list(Value), Value =/= "" ->
+ list_to_binary(Value);
+validate_option(password, Value) when is_list(Value) ->
+ Value;
+
+validate_option(cacerts, Value) when Value == undefined;
+ is_list(Value) ->
+ Value;
+%% certfile must be present in some cases otherwhise it can be set
+%% to the empty string.
+validate_option(cacertfile, undefined) ->
+ <<>>;
+validate_option(cacertfile, Value) when is_binary(Value) ->
+ Value;
+validate_option(cacertfile, Value) when is_list(Value), Value =/= ""->
+ list_to_binary(Value);
+validate_option(dh, Value) when Value == undefined;
+ is_binary(Value) ->
+ Value;
+validate_option(dhfile, undefined = Value) ->
+ Value;
+validate_option(dhfile, Value) when is_binary(Value) ->
+ Value;
+validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
+ list_to_binary(Value);
+validate_option(psk_identity, undefined) ->
+ undefined;
+validate_option(psk_identity, Identity)
+ when is_list(Identity), Identity =/= "", length(Identity) =< 65535 ->
+ list_to_binary(Identity);
+validate_option(user_lookup_fun, undefined) ->
+ undefined;
+validate_option(user_lookup_fun, {Fun, _} = Value) when is_function(Fun, 3) ->
+ Value;
+validate_option(srp_identity, undefined) ->
+ undefined;
+validate_option(srp_identity, {Username, Password})
+ when is_list(Username), is_list(Password), Username =/= "", length(Username) =< 255 ->
+ {list_to_binary(Username), list_to_binary(Password)};
+
+validate_option(ciphers, Value) when is_list(Value) ->
+ Version = tls_record:highest_protocol_version([]),
+ try cipher_suites(Version, Value)
+ catch
+ exit:_ ->
+ throw({error, {options, {ciphers, Value}}});
+ error:_->
+ throw({error, {options, {ciphers, Value}}})
+ end;
+validate_option(reuse_session, Value) when is_function(Value) ->
+ Value;
+validate_option(reuse_sessions, Value) when Value == true;
+ Value == false ->
+ Value;
+
+validate_option(secure_renegotiate, Value) when Value == true;
+ Value == false ->
+ Value;
+validate_option(renegotiate_at, Value) when is_integer(Value) ->
+ erlang:min(Value, ?DEFAULT_RENEGOTIATE_AT);
+
+validate_option(hibernate_after, undefined) ->
+ undefined;
+validate_option(hibernate_after, Value) when is_integer(Value), Value >= 0 ->
+ Value;
+validate_option(erl_dist,Value) when Value == true;
+ Value == false ->
+ Value;
+validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols} = Value)
+ when is_list(PreferredProtocols) ->
+ case tls_record:highest_protocol_version([]) of
+ {3,0} ->
+ throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
+ _ ->
+ validate_binary_list(client_preferred_next_protocols, PreferredProtocols),
+ validate_npn_ordering(Precedence),
+ {Precedence, PreferredProtocols, ?NO_PROTOCOL}
+ end;
+validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols, Default} = Value)
+ when is_list(PreferredProtocols), is_binary(Default),
+ byte_size(Default) > 0, byte_size(Default) < 256 ->
+ case tls_record:highest_protocol_version([]) of
+ {3,0} ->
+ throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
+ _ ->
+ validate_binary_list(client_preferred_next_protocols, PreferredProtocols),
+ validate_npn_ordering(Precedence),
+ Value
+ end;
+
+validate_option(client_preferred_next_protocols, undefined) ->
+ undefined;
+validate_option(next_protocols_advertised = Opt, Value) when is_list(Value) ->
+ case tls_record:highest_protocol_version([]) of
+ {3,0} ->
+ throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
+ _ ->
+ validate_binary_list(next_protocols_advertised, Value),
+ Value
+ end;
+
+validate_option(next_protocols_advertised, undefined) ->
+ undefined;
+validate_option(Opt, Value) ->
+ throw({error, {options, {Opt, Value}}}).
+
+validate_npn_ordering(client) ->
+ ok;
+validate_npn_ordering(server) ->
+ ok;
+validate_npn_ordering(Value) ->
+ throw({error, {options, {client_preferred_next_protocols, {invalid_precedence, Value}}}}).
+
+validate_binary_list(Opt, List) ->
+ lists:foreach(
+ fun(Bin) when is_binary(Bin),
+ byte_size(Bin) > 0,
+ byte_size(Bin) < 256 ->
+ ok;
+ (Bin) ->
+ throw({error, {options, {Opt, {invalid_protocol, Bin}}}})
+ end, List).
+
+validate_versions([], Versions) ->
+ Versions;
+validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1;
+ Version == sslv3 ->
+ validate_versions(Rest, Versions);
+validate_versions([Ver| _], Versions) ->
+ throw({error, {options, {Ver, {versions, Versions}}}}).
+
+validate_inet_option(mode, Value)
+ when Value =/= list, Value =/= binary ->
+ throw({error, {options, {mode,Value}}});
+validate_inet_option(packet, Value)
+ when not (is_atom(Value) orelse is_integer(Value)) ->
+ throw({error, {options, {packet,Value}}});
+validate_inet_option(packet_size, Value)
+ when not is_integer(Value) ->
+ throw({error, {options, {packet_size,Value}}});
+validate_inet_option(header, Value)
+ when not is_integer(Value) ->
+ throw({error, {options, {header,Value}}});
+validate_inet_option(active, Value)
+ when Value =/= true, Value =/= false, Value =/= once ->
+ throw({error, {options, {active,Value}}});
+validate_inet_option(_, _) ->
+ ok.
+
+%% The option cacerts overrides cacertsfile
+ca_cert_default(_,_, [_|_]) ->
+ undefined;
+ca_cert_default(verify_none, _, _) ->
+ undefined;
+ca_cert_default(verify_peer, {Fun,_}, _) when is_function(Fun) ->
+ undefined;
+%% Server that wants to verify_peer and has no verify_fun must have
+%% some trusted certs.
+ca_cert_default(verify_peer, undefined, _) ->
+ "".
+
+emulated_options() ->
+ [mode, packet, active, header, packet_size].
+
+internal_inet_values() ->
+ [{packet_size,0},{packet, 0},{header, 0},{active, false},{mode,binary}].
+
+socket_options(InetValues) ->
+ #socket_options{
+ mode = proplists:get_value(mode, InetValues, lists),
+ header = proplists:get_value(header, InetValues, 0),
+ active = proplists:get_value(active, InetValues, active),
+ packet = proplists:get_value(packet, InetValues, 0),
+ packet_size = proplists:get_value(packet_size, InetValues)
+ }.
+
+emulated_options(Opts) ->
+ emulated_options(Opts, internal_inet_values(), #socket_options{}).
+
+emulated_options([{mode,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(mode,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{mode=Opt});
+emulated_options([{header,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(header,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{header=Opt});
+emulated_options([{active,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(active,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{active=Opt});
+emulated_options([{packet,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(packet,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{packet=Opt});
+emulated_options([{packet_size,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(packet_size,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{packet_size=Opt});
+emulated_options([Opt|Opts], Inet, Emulated) ->
+ emulated_options(Opts, [Opt|Inet], Emulated);
+emulated_options([], Inet,Emulated) ->
+ {Inet, Emulated}.
+
+cipher_suites(Version, []) ->
+ ssl_cipher:suites(Version);
+cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
+ Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
+ cipher_suites(Version, Ciphers);
+cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
+ Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
+ cipher_suites(Version, Ciphers);
+
+cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
+ Supported0 = ssl_cipher:suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites(),
+ Supported = ssl_cipher:filter_suites(Supported0),
+ case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of
+ [] ->
+ Supported;
+ Ciphers ->
+ Ciphers
+ end;
+cipher_suites(Version, [Head | _] = Ciphers0) when is_list(Head) ->
+ %% Format: ["RC4-SHA","RC4-MD5"]
+ Ciphers = [ssl_cipher:openssl_suite(C) || C <- Ciphers0],
+ cipher_suites(Version, Ciphers);
+cipher_suites(Version, Ciphers0) ->
+ %% Format: "RC4-SHA:RC4-MD5"
+ Ciphers = [ssl_cipher:openssl_suite(C) || C <- string:tokens(Ciphers0, ":")],
+ cipher_suites(Version, Ciphers).
+
+unexpected_format(Error) ->
+ lists:flatten(io_lib:format("Unexpected error: ~p", [Error])).
+
+file_error_format({error, Error})->
+ case file:format_error(Error) of
+ "unknown POSIX error" ->
+ "decoding error";
+ Str ->
+ Str
+ end;
+file_error_format(_) ->
+ "decoding error".
+
+file_desc(cacertfile) ->
+ "Invalid CA certificate file ";
+file_desc(certfile) ->
+ "Invalid certificate file ";
+file_desc(keyfile) ->
+ "Invalid key file ";
+file_desc(dhfile) ->
+ "Invalid DH params file ".
+
+detect(_Pred, []) ->
+ undefined;
+detect(Pred, [H|T]) ->
+ case Pred(H) of
+ true ->
+ H;
+ _ ->
+ detect(Pred, T)
+ end.
+
+make_next_protocol_selector(undefined) ->
+ undefined;
+make_next_protocol_selector({client, AllProtocols, DefaultProtocol}) ->
+ fun(AdvertisedProtocols) ->
+ case detect(fun(PreferredProtocol) ->
+ lists:member(PreferredProtocol, AdvertisedProtocols)
+ end, AllProtocols) of
+ undefined ->
+ DefaultProtocol;
+ PreferredProtocol ->
+ PreferredProtocol
+ end
+ end;
+
+make_next_protocol_selector({server, AllProtocols, DefaultProtocol}) ->
+ fun(AdvertisedProtocols) ->
+ case detect(fun(PreferredProtocol) ->
+ lists:member(PreferredProtocol, AllProtocols)
+ end,
+ AdvertisedProtocols) of
+ undefined ->
+ DefaultProtocol;
+ PreferredProtocol ->
+ PreferredProtocol
+ end
+ end.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/tls_connection.erl
index 54eed03d3c..6a0461e805 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -25,17 +25,16 @@
%% sent according to the SSL-record protocol.
%%----------------------------------------------------------------------
--module(ssl_connection).
+-module(tls_connection).
-behaviour(gen_fsm).
--include("ssl_handshake.hrl").
+-include("tls_handshake.hrl").
-include("ssl_alert.hrl").
--include("ssl_record.hrl").
+-include("tls_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
--include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
%% Internal application API
@@ -71,7 +70,7 @@
tls_handshake_history, % tls_handshake_history()
tls_cipher_texts, % list() received but not deciphered yet
cert_db, %
- session, % #session{} from ssl_handshake.hrl
+ session, % #session{} from tls_handshake.hrl
session_cache, %
session_cache_cb, %
negotiated_version, % tls_version()
@@ -303,7 +302,7 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) ->
State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
- Handshake = ssl_handshake:init_handshake_history(),
+ Handshake = tls_handshake:init_handshake_history(),
TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}),
try ssl_init(SSLOpts0, Role) of
{ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, Key, DHParams} ->
@@ -343,11 +342,11 @@ hello(start, #state{host = Host, port = Port, role = client,
transport_cb = Transport, socket = Socket,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _}} = State0) ->
- Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
Version = Hello#client_hello.client_version,
- Handshake0 = ssl_handshake:init_handshake_history(),
+ Handshake0 = tls_handshake:init_handshake_history(),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Hello, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -375,7 +374,7 @@ hello(#server_hello{cipher_suite = CipherSuite,
negotiated_version = ReqVersion,
renegotiation = {Renegotiation, _},
ssl_options = SslOptions} = State0) ->
- case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
+ case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
#alert{} = Alert ->
handle_own_alert(Alert, ReqVersion, hello, State0);
{Version, NewId, ConnectionStates, NextProtocol} ->
@@ -415,7 +414,7 @@ hello(Hello = #client_hello{client_version = ClientVersion},
session_cache = Cache,
session_cache_cb = CacheCb,
ssl_options = SslOpts}) ->
- case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
+ case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
{Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise,
EcPointFormats, EllipticCurves} ->
@@ -449,11 +448,11 @@ abbreviated(#finished{verify_data = Data} = Finished,
session = #session{master_secret = MasterSecret},
connection_states = ConnectionStates0} =
State) ->
- case ssl_handshake:verify_connection(Version, Finished, client,
+ case tls_handshake:verify_connection(Version, Finished, client,
get_current_connection_state_prf(ConnectionStates0, write),
MasterSecret, Handshake) of
verified ->
- ConnectionStates = ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0),
+ ConnectionStates = tls_record:set_client_verify_data(current_both, Data, ConnectionStates0),
next_state_connection(abbreviated,
ack_connection(State#state{connection_states = ConnectionStates}));
#alert{} = Alert ->
@@ -465,11 +464,11 @@ abbreviated(#finished{verify_data = Data} = Finished,
session = #session{master_secret = MasterSecret},
negotiated_version = Version,
connection_states = ConnectionStates0} = State) ->
- case ssl_handshake:verify_connection(Version, Finished, server,
+ case tls_handshake:verify_connection(Version, Finished, server,
get_pending_connection_state_prf(ConnectionStates0, write),
MasterSecret, Handshake0) of
verified ->
- ConnectionStates1 = ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0),
+ ConnectionStates1 = tls_record:set_server_verify_data(current_read, Data, ConnectionStates0),
{ConnectionStates, Handshake} =
finalize_handshake(State#state{connection_states = ConnectionStates1}, abbreviated),
next_state_connection(abbreviated,
@@ -524,7 +523,7 @@ certify(#certificate{} = Cert,
cert_db = CertDbHandle,
cert_db_ref = CertDbRef,
ssl_options = Opts} = State) ->
- case ssl_handshake:certify(Cert, CertDbHandle, CertDbRef, Opts#ssl_options.depth,
+ case tls_handshake:certify(Cert, CertDbHandle, CertDbRef, Opts#ssl_options.depth,
Opts#ssl_options.verify,
Opts#ssl_options.verify_fun, Role) of
{PeerCert, PublicKeyInfo} ->
@@ -604,7 +603,7 @@ certify(#server_hello_done{},
negotiated_version = Version,
premaster_secret = undefined,
role = client} = State0) ->
- case ssl_handshake:master_secret(Version, Session,
+ case tls_handshake:master_secret(Version, Session,
ConnectionStates0, client) of
{MasterSecret, ConnectionStates} ->
State = State0#state{connection_states = ConnectionStates},
@@ -620,7 +619,7 @@ certify(#server_hello_done{},
negotiated_version = Version,
premaster_secret = PremasterSecret,
role = client} = State0) ->
- case ssl_handshake:master_secret(Version, PremasterSecret,
+ case tls_handshake:master_secret(Version, PremasterSecret,
ConnectionStates0, client) of
{MasterSecret, ConnectionStates} ->
Session = Session0#session{master_secret = MasterSecret},
@@ -641,7 +640,7 @@ certify(#client_key_exchange{} = Msg,
certify(#client_key_exchange{exchange_keys = Keys},
State = #state{key_algorithm = KeyAlg, negotiated_version = Version}) ->
try
- certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, Version), State)
+ certify_client_key_exchange(tls_handshake:decode_client_key(Keys, KeyAlg, Version), State)
catch
#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State)
@@ -659,8 +658,8 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
connection_states = ConnectionStates0,
session = Session0,
private_key = Key} = State0) ->
- PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
- case ssl_handshake:master_secret(Version, PremasterSecret,
+ PremasterSecret = tls_handshake:decrypt_premaster_secret(EncPMS, Key),
+ case tls_handshake:master_secret(Version, PremasterSecret,
ConnectionStates0, server) of
{MasterSecret, ConnectionStates} ->
Session = Session0#session{master_secret = MasterSecret},
@@ -727,7 +726,7 @@ certify_client_key_exchange(#client_rsa_psk_identity{
#encrypted_premaster_secret{premaster_secret= EncPMS}},
#state{negotiated_version = Version,
private_key = Key} = State0) ->
- PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
+ PremasterSecret = tls_handshake:decrypt_premaster_secret(EncPMS, Key),
case server_rsa_psk_master_secret(PskIdentity, PremasterSecret, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
@@ -770,7 +769,7 @@ cipher(#certificate_verify{signature = Signature, hashsign_algorithm = CertHashS
{_, _} -> CertHashSign;
_ -> ConnectionHashSign
end,
- case ssl_handshake:certificate_verify(Signature, PublicKeyInfo,
+ case tls_handshake:certificate_verify(Signature, PublicKeyInfo,
Version, HashSign, MasterSecret, Handshake) of
valid ->
{Record, State} = next_record(State0),
@@ -793,7 +792,7 @@ cipher(#finished{verify_data = Data} = Finished,
= Session0,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0} = State) ->
- case ssl_handshake:verify_connection(Version, Finished,
+ case tls_handshake:verify_connection(Version, Finished,
opposite_role(Role),
get_current_connection_state_prf(ConnectionStates0, read),
MasterSecret, Handshake0) of
@@ -831,7 +830,7 @@ connection(#hello_request{}, #state{host = Host, port = Port,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _},
tls_handshake_history = Handshake0} = State0) ->
- Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
{BinMsg, ConnectionStates, Handshake} =
@@ -1026,7 +1025,7 @@ handle_sync_event({prf, Secret, Label, Seed, WantedLength}, _, StateName,
#state{connection_states = ConnectionStates,
negotiated_version = Version} = State) ->
ConnectionState =
- ssl_record:current_connection_state(ConnectionStates, read),
+ tls_record:current_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{master_secret = MasterSecret,
client_random = ClientRandom,
@@ -1041,7 +1040,7 @@ handle_sync_event({prf, Secret, Label, Seed, WantedLength}, _, StateName,
(client_random, Acc) -> [ClientRandom|Acc];
(server_random, Acc) -> [ServerRandom|Acc]
end, [], Seed)),
- ssl_handshake:prf(Version, SecretToUse, Label, SeedToUse, WantedLength)
+ tls_handshake:prf(Version, SecretToUse, Label, SeedToUse, WantedLength)
catch
exit:_ -> {error, badarg};
error:Reason -> {error, Reason}
@@ -1052,7 +1051,7 @@ handle_sync_event(info, _, StateName,
#state{negotiated_version = Version,
session = #session{cipher_suite = Suite}} = State) ->
- AtomVersion = ssl_record:protocol_version(Version),
+ AtomVersion = tls_record:protocol_version(Version),
{reply, {ok, {AtomVersion, ssl:suite_definition(Suite)}},
StateName, State, get_timeout(State)};
@@ -1398,7 +1397,7 @@ certify_client(#state{client_certificate_requested = true, role = client,
session = #session{own_certificate = OwnCert},
socket = Socket,
tls_handshake_history = Handshake0} = State) ->
- Certificate = ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, client),
+ Certificate = tls_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, client),
{BinCert, ConnectionStates, Handshake} =
encode_handshake(Certificate, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinCert),
@@ -1419,7 +1418,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
tls_handshake_history = Handshake0} = State) ->
%%TODO: for TLS 1.2 we can choose a different/stronger HashSign combination for this.
- case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret,
+ case tls_handshake:client_certificate_verify(OwnCert, MasterSecret,
Version, HashSign, PrivateKey, Handshake0) of
#certificate_verify{} = Verified ->
{BinVerified, ConnectionStates, Handshake} =
@@ -1445,7 +1444,7 @@ do_server_hello(Type, NextProtocolsToSend,
= State0) when is_atom(Type) ->
ServerHello =
- ssl_handshake:server_hello(SessId, Version,
+ tls_handshake:server_hello(SessId, Version,
ConnectionStates0, Renegotiation,
NextProtocolsToSend, EcPointFormats, EllipticCurves),
State = server_hello(ServerHello,
@@ -1481,7 +1480,7 @@ resumed_server_hello(#state{session = Session,
connection_states = ConnectionStates0,
negotiated_version = Version} = State0) ->
- case ssl_handshake:master_secret(Version, Session,
+ case tls_handshake:master_secret(Version, Session,
ConnectionStates0, server) of
{_, ConnectionStates1} ->
State1 = State0#state{connection_states = ConnectionStates1,
@@ -1510,7 +1509,7 @@ handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
session_cache = Cache,
session_cache_cb = CacheCb} = State0) ->
Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}),
- case ssl_handshake:master_secret(Version, Session,
+ case tls_handshake:master_secret(Version, Session,
ConnectionStates0, client) of
{_, ConnectionStates} ->
{Record, State} =
@@ -1570,7 +1569,7 @@ server_hello_done(#state{transport_cb = Transport,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0} = State) ->
- HelloDone = ssl_handshake:server_hello_done(),
+ HelloDone = tls_handshake:server_hello_done(),
{BinHelloDone, ConnectionStates, Handshake} =
encode_handshake(HelloDone, Version, ConnectionStates0, Handshake0),
@@ -1590,7 +1589,7 @@ certify_server(#state{transport_cb = Transport,
cert_db = CertDbHandle,
cert_db_ref = CertDbRef,
session = #session{own_certificate = OwnCert}} = State) ->
- case ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, server) of
+ case tls_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, server) of
CertMsg = #certificate{} ->
{BinCertMsg, ConnectionStates, Handshake} =
encode_handshake(CertMsg, Version, ConnectionStates0, Handshake0),
@@ -1619,11 +1618,11 @@ key_exchange(#state{role = server, key_algorithm = Algo,
Algo == dh_anon ->
DHKeys = public_key:generate_key(Params),
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
+ Msg = tls_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1651,11 +1650,11 @@ key_exchange(#state{role = server, key_algorithm = Algo,
ECDHKeys = public_key:generate_key(select_curve(State)),
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
+ Msg = tls_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1680,14 +1679,14 @@ key_exchange(#state{role = server, key_algorithm = psk,
transport_cb = Transport
} = State) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
- HashSignAlgo, ClientRandom,
- ServerRandom,
- PrivateKey}),
+ Msg = tls_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1707,11 +1706,11 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
} = State) ->
DHKeys = public_key:generate_key(Params),
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
+ Msg = tls_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1736,11 +1735,11 @@ key_exchange(#state{role = server, key_algorithm = rsa_psk,
transport_cb = Transport
} = State) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
+ Msg = tls_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1772,11 +1771,11 @@ key_exchange(#state{role = server, key_algorithm = Algo,
Keys0
end,
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {srp, Keys, SrpParams,
+ Msg = tls_handshake:key_exchange(server, Version, {srp, Keys, SrpParams,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1812,7 +1811,7 @@ key_exchange(#state{role = client,
when Algorithm == dhe_dss;
Algorithm == dhe_rsa;
Algorithm == dh_anon ->
- Msg = ssl_handshake:key_exchange(client, Version, {dh, DhPubKey}),
+ Msg = tls_handshake:key_exchange(client, Version, {dh, DhPubKey}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1829,7 +1828,7 @@ key_exchange(#state{role = client,
when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
Algorithm == ecdh_anon ->
- Msg = ssl_handshake:key_exchange(client, Version, {ecdh, Keys}),
+ Msg = tls_handshake:key_exchange(client, Version, {ecdh, Keys}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1843,7 +1842,7 @@ key_exchange(#state{role = client,
negotiated_version = Version,
socket = Socket, transport_cb = Transport,
tls_handshake_history = Handshake0} = State) ->
- Msg = ssl_handshake:key_exchange(client, Version, {psk, SslOpts#ssl_options.psk_identity}),
+ Msg = tls_handshake:key_exchange(client, Version, {psk, SslOpts#ssl_options.psk_identity}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1858,7 +1857,7 @@ key_exchange(#state{role = client,
diffie_hellman_keys = {DhPubKey, _},
socket = Socket, transport_cb = Transport,
tls_handshake_history = Handshake0} = State) ->
- Msg = ssl_handshake:key_exchange(client, Version, {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}),
+ Msg = tls_handshake:key_exchange(client, Version, {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1891,7 +1890,7 @@ key_exchange(#state{role = client,
when Algorithm == srp_dss;
Algorithm == srp_rsa;
Algorithm == srp_anon ->
- Msg = ssl_handshake:key_exchange(client, Version, {srp, ClientPubKey}),
+ Msg = tls_handshake:key_exchange(client, Version, {srp, ClientPubKey}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1908,7 +1907,7 @@ rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
Algorithm == ?sha384WithRSAEncryption;
Algorithm == ?sha512WithRSAEncryption
->
- ssl_handshake:key_exchange(client, Version,
+ tls_handshake:key_exchange(client, Version,
{premaster_secret, PremasterSecret,
PublicKeyInfo});
rsa_key_exchange(_, _, _) ->
@@ -1924,7 +1923,7 @@ rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, PublicKeyInfo = {Alg
Algorithm == ?sha384WithRSAEncryption;
Algorithm == ?sha512WithRSAEncryption
->
- ssl_handshake:key_exchange(client, Version,
+ tls_handshake:key_exchange(client, Version,
{psk_premaster_secret, PskIdentity, PremasterSecret,
PublicKeyInfo});
rsa_psk_key_exchange(_, _, _, _) ->
@@ -1938,7 +1937,7 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer},
negotiated_version = Version,
socket = Socket,
transport_cb = Transport} = State) ->
- Msg = ssl_handshake:certificate_request(ConnectionStates0, CertDbHandle, CertDbRef),
+ Msg = tls_handshake:certificate_request(ConnectionStates0, CertDbHandle, CertDbRef),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1953,7 +1952,7 @@ finalize_handshake(State, StateName) ->
ConnectionStates0 = cipher_protocol(State),
ConnectionStates =
- ssl_record:activate_pending_connection_state(ConnectionStates0,
+ tls_record:activate_pending_connection_state(ConnectionStates0,
write),
State1 = State#state{connection_states = ConnectionStates},
@@ -1971,7 +1970,7 @@ next_protocol(#state{transport_cb = Transport, socket = Socket,
next_protocol = NextProtocol,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0} = State) ->
- NextProtocolMessage = ssl_handshake:next_protocol(NextProtocol),
+ NextProtocolMessage = tls_handshake:next_protocol(NextProtocol),
{BinMsg, ConnectionStates, Handshake} = encode_handshake(NextProtocolMessage, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
@@ -1993,7 +1992,7 @@ finished(#state{role = Role, socket = Socket, negotiated_version = Version,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0}, StateName) ->
MasterSecret = Session#session.master_secret,
- Finished = ssl_handshake:finished(Version, Role,
+ Finished = tls_handshake:finished(Version, Role,
get_current_connection_state_prf(ConnectionStates0, write),
MasterSecret, Handshake0),
ConnectionStates1 = save_verify_data(Role, Finished, ConnectionStates0, StateName),
@@ -2003,18 +2002,18 @@ finished(#state{role = Role, socket = Socket, negotiated_version = Version,
{ConnectionStates, Handshake}.
save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, certify) ->
- ssl_record:set_client_verify_data(current_write, Data, ConnectionStates);
+ tls_record:set_client_verify_data(current_write, Data, ConnectionStates);
save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, cipher) ->
- ssl_record:set_server_verify_data(current_both, Data, ConnectionStates);
+ tls_record:set_server_verify_data(current_both, Data, ConnectionStates);
save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, abbreviated) ->
- ssl_record:set_client_verify_data(current_both, Data, ConnectionStates);
+ tls_record:set_client_verify_data(current_both, Data, ConnectionStates);
save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbreviated) ->
- ssl_record:set_server_verify_data(current_write, Data, ConnectionStates).
+ tls_record:set_server_verify_data(current_write, Data, ConnectionStates).
handle_server_key(#server_key_exchange{exchange_keys = Keys},
#state{key_algorithm = KeyAlg,
negotiated_version = Version} = State) ->
- Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version),
+ Params = tls_handshake:decode_server_key(Keys, KeyAlg, Version),
HashSign = connection_hashsign(Params#server_key_params.hashsign, State),
case HashSign of
{_, SignAlgo} when SignAlgo == anon; SignAlgo == ecdh_anon ->
@@ -2031,15 +2030,15 @@ verify_server_key(#server_key_params{params = Params,
public_key_info = PubKeyInfo,
connection_states = ConnectionStates} = State) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Hash = ssl_handshake:server_key_exchange_hash(HashAlgo,
+ Hash = tls_handshake:server_key_exchange_hash(HashAlgo,
<<ClientRandom/binary,
ServerRandom/binary,
EncParams/binary>>),
- case ssl_handshake:verify_signature(Version, Hash, HashSign, Signature, PubKeyInfo) of
+ case tls_handshake:verify_signature(Version, Hash, HashSign, Signature, PubKeyInfo) of
true ->
server_master_secret(Params, State);
false ->
@@ -2075,7 +2074,7 @@ master_from_premaster_secret(PremasterSecret,
#state{session = Session,
negotiated_version = Version, role = Role,
connection_states = ConnectionStates0} = State) ->
- case ssl_handshake:master_secret(Version, PremasterSecret,
+ case tls_handshake:master_secret(Version, PremasterSecret,
ConnectionStates0, Role) of
{MasterSecret, ConnectionStates} ->
State#state{
@@ -2216,7 +2215,7 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys,
case ssl_srp_primes:check_srp_params(Generator, Prime) of
ok ->
{Username, Password} = SslOpts#ssl_options.srp_identity,
- DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ DerivedKey = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
case crypto:compute_key(srp, ServerPub, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
@@ -2228,12 +2227,12 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys,
end.
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
- ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
+ ConnectionStates = tls_record:set_server_verify_data(current_both, Data, ConnectionStates0),
next_state_connection(cipher, ack_connection(State#state{session = Session,
connection_states = ConnectionStates}));
cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
- ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, ConnectionStates0),
+ ConnectionStates1 = tls_record:set_client_verify_data(current_read, Data, ConnectionStates0),
{ConnectionStates, Handshake} =
finalize_handshake(State#state{connection_states = ConnectionStates1,
session = Session}, cipher),
@@ -2243,16 +2242,16 @@ cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0
tls_handshake_history =
Handshake})).
encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
- ssl_record:encode_alert_record(Alert, Version, ConnectionStates).
+ tls_record:encode_alert_record(Alert, Version, ConnectionStates).
encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
- ssl_record:encode_change_cipher_spec(Version, ConnectionStates).
+ tls_record:encode_change_cipher_spec(Version, ConnectionStates).
encode_handshake(HandshakeRec, Version, ConnectionStates0, Handshake0) ->
- Frag = ssl_handshake:encode_handshake(HandshakeRec, Version),
- Handshake1 = ssl_handshake:update_handshake_history(Handshake0, Frag),
+ Frag = tls_handshake:encode_handshake(HandshakeRec, Version),
+ Handshake1 = tls_handshake:update_handshake_history(Handshake0, Frag),
{E, ConnectionStates1} =
- ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
+ tls_record:encode_handshake(Frag, Version, ConnectionStates0),
{E, ConnectionStates1, Handshake1}.
encode_packet(Data, #socket_options{packet=Packet}) ->
@@ -2347,7 +2346,7 @@ write_application_data(Data0, From, #state{socket = Socket,
renegotiate(State#state{send_queue = queue:in_r({From, Data}, SendQueue),
renegotiation = {true, internal}});
false ->
- {Msgs, ConnectionStates} = ssl_record:encode_data(Data, Version, ConnectionStates0),
+ {Msgs, ConnectionStates} = tls_record:encode_data(Data, Version, ConnectionStates0),
Result = Transport:send(Socket, Msgs),
{reply, Result,
connection, State#state{connection_states = ConnectionStates}, get_timeout(State)}
@@ -2515,7 +2514,7 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
fun({#hello_request{} = Packet, _}, {next_state, connection = SName, State}) ->
%% This message should not be included in handshake
%% message hashes. Starts new handshake (renegotiation)
- Hs0 = ssl_handshake:init_handshake_history(),
+ Hs0 = tls_handshake:init_handshake_history(),
?MODULE:SName(Packet, State#state{tls_handshake_history=Hs0,
renegotiation = {true, peer}});
({#hello_request{} = Packet, _}, {next_state, SName, State}) ->
@@ -2524,17 +2523,17 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
?MODULE:SName(Packet, State);
({#client_hello{} = Packet, Raw}, {next_state, connection = SName, State}) ->
Version = Packet#client_hello.client_version,
- Hs0 = ssl_handshake:init_handshake_history(),
- Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
+ Hs0 = tls_handshake:init_handshake_history(),
+ Hs1 = tls_handshake:update_handshake_history(Hs0, Raw),
?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1,
renegotiation = {true, peer}});
({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_history=Hs0}}) ->
- Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
+ Hs1 = tls_handshake:update_handshake_history(Hs0, Raw),
?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1});
(_, StopState) -> StopState
end,
try
- {Packets, Buf} = ssl_handshake:get_tls_handshake(Version,Data,Buf0),
+ {Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0),
State = State0#state{tls_packets = Packets, tls_handshake_buffer = Buf},
handle_tls_handshake(Handle, Next, State)
catch throw:#alert{} = Alert ->
@@ -2552,7 +2551,7 @@ next_state(Current, Next, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>}
_ChangeCipher,
#state{connection_states = ConnectionStates0} = State0) ->
ConnectionStates1 =
- ssl_record:activate_pending_connection_state(ConnectionStates0, read),
+ tls_record:activate_pending_connection_state(ConnectionStates0, read),
{Record, State} = next_record(State0#state{connection_states = ConnectionStates1}),
next_state(Current, Next, Record, State);
next_state(Current, Next, #ssl_tls{type = _Unknown}, State0) ->
@@ -2562,7 +2561,7 @@ next_state(Current, Next, #ssl_tls{type = _Unknown}, State0) ->
next_tls_record(Data, #state{tls_record_buffer = Buf0,
tls_cipher_texts = CT0} = State0) ->
- case ssl_record:get_tls_records(Data, Buf0) of
+ case tls_record:get_tls_records(Data, Buf0) of
{Records, Buf1} ->
CT1 = CT0 ++ Records,
next_record(State0#state{tls_record_buffer = Buf1,
@@ -2577,7 +2576,7 @@ next_record(#state{tls_packets = [], tls_cipher_texts = [], socket = Socket,
{no_record, State};
next_record(#state{tls_packets = [], tls_cipher_texts = [CT | Rest],
connection_states = ConnStates0} = State) ->
- case ssl_record:decode_cipher_text(CT, ConnStates0) of
+ case tls_record:decode_cipher_text(CT, ConnStates0) of
{Plain, ConnStates} ->
{Plain, State#state{tls_cipher_texts = Rest, connection_states = ConnStates}};
#alert{} = Alert ->
@@ -2604,7 +2603,7 @@ next_state_connection(StateName, #state{send_queue = Queue0,
case queue:out(Queue0) of
{{value, {From, Data}}, Queue} ->
{Msgs, ConnectionStates} =
- ssl_record:encode_data(Data, Version, ConnectionStates0),
+ tls_record:encode_data(Data, Version, ConnectionStates0),
Result = Transport:send(Socket, Msgs),
gen_fsm:reply(From, Result),
next_state_connection(StateName,
@@ -2623,13 +2622,13 @@ next_state_is_connection(_, State =
#socket_options{active = false}}) when RecvFrom =/= undefined ->
passive_receive(State#state{premaster_secret = undefined,
public_key_info = undefined,
- tls_handshake_history = ssl_handshake:init_handshake_history()}, connection);
+ tls_handshake_history = tls_handshake:init_handshake_history()}, connection);
next_state_is_connection(StateName, State0) ->
{Record, State} = next_record_if_active(State0),
next_state(StateName, connection, Record, State#state{premaster_secret = undefined,
public_key_info = undefined,
- tls_handshake_history = ssl_handshake:init_handshake_history()}).
+ tls_handshake_history = tls_handshake:init_handshake_history()}).
register_session(client, Host, Port, #session{is_resumable = new} = Session0) ->
Session = Session0#session{is_resumable = true},
@@ -2649,7 +2648,7 @@ invalidate_session(server, _, Port, Session) ->
initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
{CbModule, DataTag, CloseTag, ErrorTag}) ->
- ConnectionStates = ssl_record:init_connection_states(Role),
+ ConnectionStates = tls_record:init_connection_states(Role),
SessionCacheCb = case application:get_env(ssl, session_cb) of
{ok, Cb} when is_atom(Cb) ->
@@ -2906,18 +2905,18 @@ ack_connection(State) ->
renegotiate(#state{role = client} = State) ->
%% Handle same way as if server requested
%% the renegotiation
- Hs0 = ssl_handshake:init_handshake_history(),
+ Hs0 = tls_handshake:init_handshake_history(),
connection(#hello_request{}, State#state{tls_handshake_history = Hs0});
renegotiate(#state{role = server,
socket = Socket,
transport_cb = Transport,
negotiated_version = Version,
connection_states = ConnectionStates0} = State0) ->
- HelloRequest = ssl_handshake:hello_request(),
- Frag = ssl_handshake:encode_handshake(HelloRequest, Version),
- Hs0 = ssl_handshake:init_handshake_history(),
+ HelloRequest = tls_handshake:hello_request(),
+ Frag = tls_handshake:encode_handshake(HelloRequest, Version),
+ Hs0 = tls_handshake:init_handshake_history(),
{BinMsg, ConnectionStates} =
- ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
+ tls_record:encode_handshake(Frag, Version, ConnectionStates0),
Transport:send(Socket, BinMsg),
{Record, State} = next_record(State0#state{connection_states =
ConnectionStates,
@@ -2977,14 +2976,14 @@ handle_trusted_certs_db(#state{cert_db_ref = Ref,
ssl_options = #ssl_options{cacertfile = undefined}}) ->
%% Certs provided as DER directly can not be shared
%% with other connections and it is safe to delete them when the connection ends.
- ssl_certificate_db:remove_trusted_certs(Ref, CertDb);
+ ssl_pkix_db:remove_trusted_certs(Ref, CertDb);
handle_trusted_certs_db(#state{file_ref_db = undefined}) ->
%% Something went wrong early (typically cacertfile does not exist) so there is nothing to handle
ok;
handle_trusted_certs_db(#state{cert_db_ref = Ref,
file_ref_db = RefDb,
ssl_options = #ssl_options{cacertfile = File}}) ->
- case ssl_certificate_db:ref_count(Ref, RefDb, -1) of
+ case ssl_pkix_db:ref_count(Ref, RefDb, -1) of
0 ->
ssl_manager:clean_cert_db(Ref, File);
_ ->
@@ -2992,10 +2991,10 @@ handle_trusted_certs_db(#state{cert_db_ref = Ref,
end.
get_current_connection_state_prf(CStates, Direction) ->
- CS = ssl_record:current_connection_state(CStates, Direction),
+ CS = tls_record:current_connection_state(CStates, Direction),
CS#connection_state.security_parameters#security_parameters.prf_algorithm.
get_pending_connection_state_prf(CStates, Direction) ->
- CS = ssl_record:pending_connection_state(CStates, Direction),
+ CS = tls_record:pending_connection_state(CStates, Direction),
CS#connection_state.security_parameters#security_parameters.prf_algorithm.
connection_hashsign(HashSign = {_, _}, _State) ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/tls_handshake.erl
index e358cbe9bb..fea75736f7 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -21,10 +21,10 @@
%% Purpose: Help funtions for handling the SSL-handshake protocol
%%----------------------------------------------------------------------
--module(ssl_handshake).
+-module(tls_handshake).
--include("ssl_handshake.hrl").
--include("ssl_record.hrl").
+-include("tls_handshake.hrl").
+-include("tls_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
@@ -64,8 +64,8 @@ client_hello(Host, Port, ConnectionStates,
ciphers = UserSuites
} = SslOpts,
Cache, CacheCb, Renegotiation, OwnCert) ->
- Version = ssl_record:highest_protocol_version(Versions),
- Pending = ssl_record:pending_connection_state(ConnectionStates, read),
+ Version = tls_record:highest_protocol_version(Versions),
+ Pending = tls_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
SRP = srp_user(SslOpts),
@@ -76,7 +76,7 @@ client_hello(Host, Port, ConnectionStates,
#client_hello{session_id = Id,
client_version = Version,
cipher_suites = cipher_suites(Ciphers, Renegotiation),
- compression_methods = ssl_record:compressions(),
+ compression_methods = tls_record:compressions(),
random = SecParams#security_parameters.client_random,
renegotiation_info =
@@ -109,7 +109,7 @@ encode_protocols_advertised_on_server(Protocols) ->
%%--------------------------------------------------------------------
server_hello(SessionId, Version, ConnectionStates, Renegotiation,
ProtocolsAdvertisedOnServer, EcPointFormats, EllipticCurves) ->
- Pending = ssl_record:pending_connection_state(ConnectionStates, read),
+ Pending = tls_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
#server_hello{server_version = Version,
cipher_suite = SecParams#security_parameters.cipher_suite,
@@ -153,7 +153,7 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
versions = SupportedVersions},
ConnectionStates0, Renegotiation) ->
%%TODO: select hash and signature algorigthm
- case ssl_record:is_acceptable_version(Version, SupportedVersions) of
+ case tls_record:is_acceptable_version(Version, SupportedVersions) of
true ->
case handle_renegotiation_info(client, Info, ConnectionStates0,
Renegotiation, SecureRenegotation, []) of
@@ -179,7 +179,7 @@ hello(#client_hello{client_version = ClientVersion} = Hello,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
%% TODO: select hash and signature algorithm
Version = select_version(ClientVersion, Versions),
- case ssl_record:is_acceptable_version(Version, Versions) of
+ case tls_record:is_acceptable_version(Version, Versions) of
true ->
%% TODO: need to take supported Curves into Account when selecting the CipherSuite....
%% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers
@@ -357,7 +357,7 @@ verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, {?'id-ecPublicKey
certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
#connection_state{security_parameters =
#security_parameters{cipher_suite = CipherSuite}} =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
Types = certificate_types(CipherSuite),
HashSigns = default_hash_signs(),
Authorities = certificate_authorities(CertDbHandle, CertDbRef),
@@ -499,7 +499,7 @@ enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
master_secret(Version, #session{master_secret = Mastersecret},
ConnectionStates, Role) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
try master_secret(Version, Mastersecret, SecParams,
ConnectionStates, Role)
@@ -513,7 +513,7 @@ master_secret(Version, #session{master_secret = Mastersecret},
master_secret(Version, PremasterSecret, ConnectionStates, Role) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{prf_algorithm = PrfAlgo,
client_random = ClientRandom,
@@ -760,7 +760,7 @@ srp_user(_) ->
renegotiation_info(client, _, false) ->
#renegotiation_info{renegotiated_connection = undefined};
renegotiation_info(server, ConnectionStates, false) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
case CS#connection_state.secure_renegotiation of
true ->
#renegotiation_info{renegotiated_connection = ?byte(0)};
@@ -768,7 +768,7 @@ renegotiation_info(server, ConnectionStates, false) ->
#renegotiation_info{renegotiated_connection = undefined}
end;
renegotiation_info(client, ConnectionStates, true) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
case CS#connection_state.secure_renegotiation of
true ->
Data = CS#connection_state.client_verify_data,
@@ -778,7 +778,7 @@ renegotiation_info(client, ConnectionStates, true) ->
end;
renegotiation_info(server, ConnectionStates, true) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
case CS#connection_state.secure_renegotiation of
true ->
CData = CS#connection_state.client_verify_data,
@@ -840,7 +840,8 @@ select_next_protocol(Protocols, NextProtocolSelector) ->
end.
default_ecc_extensions(Version) ->
- case proplists:get_bool(ec, crypto:algorithms()) of
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
true ->
EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]},
EllipticCurves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)},
@@ -850,7 +851,8 @@ default_ecc_extensions(Version) ->
end.
handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) ->
- case proplists:get_bool(ec, crypto:algorithms()) of
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
true ->
EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0),
EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0),
@@ -871,22 +873,22 @@ handle_ecc_curves_extension(Version, _) ->
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
- {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
+ {ok, tls_record:set_renegotiation_flag(true, ConnectionStates)};
handle_renegotiation_info(server, undefined, ConnectionStates, _, _, CipherSuites) ->
case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of
true ->
- {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
+ {ok, tls_record:set_renegotiation_flag(true, ConnectionStates)};
false ->
- {ok, ssl_record:set_renegotiation_flag(false, ConnectionStates)}
+ {ok, tls_record:set_renegotiation_flag(false, ConnectionStates)}
end;
handle_renegotiation_info(_, undefined, ConnectionStates, false, _, _) ->
- {ok, ssl_record:set_renegotiation_flag(false, ConnectionStates)};
+ {ok, tls_record:set_renegotiation_flag(false, ConnectionStates)};
handle_renegotiation_info(client, #renegotiation_info{renegotiated_connection = ClientServerVerify},
ConnectionStates, true, _, _) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
CData = CS#connection_state.client_verify_data,
SData = CS#connection_state.server_verify_data,
case <<CData/binary, SData/binary>> == ClientServerVerify of
@@ -902,7 +904,7 @@ handle_renegotiation_info(server, #renegotiation_info{renegotiated_connection =
true ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
false ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
Data = CS#connection_state.client_verify_data,
case Data == ClientVerify of
true ->
@@ -924,7 +926,7 @@ handle_renegotiation_info(server, undefined, ConnectionStates, true, SecureReneg
end.
handle_renegotiation_info(ConnectionStates, SecureRenegotation) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
case {SecureRenegotation, CS#connection_state.secure_renegotiation} of
{_, true} ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
@@ -941,9 +943,9 @@ handle_renegotiation_info(ConnectionStates, SecureRenegotation) ->
hello_pending_connection_states(Role, Version, CipherSuite, Random, Compression,
ConnectionStates) ->
ReadState =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
WriteState =
- ssl_record:pending_connection_state(ConnectionStates, write),
+ tls_record:pending_connection_state(ConnectionStates, write),
NewReadSecParams =
hello_security_parameters(Role, Version, ReadState, CipherSuite,
@@ -953,7 +955,7 @@ hello_pending_connection_states(Role, Version, CipherSuite, Random, Compression,
hello_security_parameters(Role, Version, WriteState, CipherSuite,
Random, Compression),
- ssl_record:update_security_params(NewReadSecParams,
+ tls_record:update_security_params(NewReadSecParams,
NewWriteSecParams,
ConnectionStates).
@@ -976,8 +978,8 @@ hello_security_parameters(server, Version, ConnectionState, CipherSuite, Random,
}.
select_version(ClientVersion, Versions) ->
- ServerVersion = ssl_record:highest_protocol_version(Versions),
- ssl_record:lowest_protocol_version(ClientVersion, ServerVersion).
+ ServerVersion = tls_record:highest_protocol_version(Versions),
+ tls_record:lowest_protocol_version(ClientVersion, ServerVersion).
select_cipher_suite([], _) ->
no_suite;
@@ -1009,15 +1011,15 @@ master_secret(Version, MasterSecret, #security_parameters{
setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom,
ClientRandom, HashSize, KML, EKML, IVS),
- ConnStates1 = ssl_record:set_master_secret(MasterSecret, ConnectionStates),
+ ConnStates1 = tls_record:set_master_secret(MasterSecret, ConnectionStates),
ConnStates2 =
- ssl_record:set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret,
+ tls_record:set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret,
Role, ConnStates1),
ClientCipherState = #cipher_state{iv = ClientIV, key = ClientWriteKey},
ServerCipherState = #cipher_state{iv = ServerIV, key = ServerWriteKey},
{MasterSecret,
- ssl_record:set_pending_cipher_state(ConnStates2, ClientCipherState,
+ tls_record:set_pending_cipher_state(ConnStates2, ClientCipherState,
ServerCipherState, Role)}.
@@ -1683,7 +1685,7 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
(_, Acc) ->
Acc
end,
- ssl_certificate_db:foldl(ConnectionCerts, [], CertDbHandle).
+ ssl_pkix_db:foldl(ConnectionCerts, [], CertDbHandle).
digitally_signed({3, Minor}, Hash, HashAlgo, Key) when Minor >= 3 ->
@@ -1767,7 +1769,8 @@ default_hash_signs() ->
?TLSEXT_SIGALG(sha),
?TLSEXT_SIGALG_DSA(sha),
?TLSEXT_SIGALG_RSA(md5)],
- HasECC = proplists:get_bool(ec, crypto:algorithms()),
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ HasECC = proplists:get_bool(ecdsa, CryptoSupport),
#hash_sign_algos{hash_sign_algos =
lists:filter(fun({_, ecdsa}) -> HasECC;
(_) -> true end, HashSigns)}.
diff --git a/lib/ssl/src/tls_handshake.hrl b/lib/ssl/src/tls_handshake.hrl
new file mode 100644
index 0000000000..abf1b5abb6
--- /dev/null
+++ b/lib/ssl/src/tls_handshake.hrl
@@ -0,0 +1,45 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the TLS-handshake protocol
+%% see RFC 5246.
+%%----------------------------------------------------------------------
+-ifndef(tls_handshake).
+-define(tls_handshake, true).
+
+-include("ssl_handshake.hrl"). %% Common TLS and DTLS records and Constantes
+
+-record(client_hello, {
+ client_version,
+ random,
+ session_id, % opaque SessionID<0..32>
+ cipher_suites, % cipher_suites<2..2^16-1>
+ compression_methods, % compression_methods<1..2^8-1>,
+ %% Extensions
+ renegotiation_info,
+ hash_signs, % supported combinations of hashes/signature algos
+ next_protocol_negotiation = undefined, % [binary()]
+ srp,
+ ec_point_formats,
+ elliptic_curves
+ }).
+
+-endif. % -ifdef(tls_handshake).
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/tls_record.erl
index 50b1b2cda9..1409a04763 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -23,12 +23,12 @@
%%
%%----------------------------------------------------------------------
--module(ssl_record).
+-module(tls_record).
--include("ssl_record.hrl").
+-include("tls_record.hrl").
-include("ssl_internal.hrl").
-include("ssl_alert.hrl").
--include("ssl_handshake.hrl").
+-include("tls_handshake.hrl").
-include("ssl_cipher.hrl").
%% Connection state handling
@@ -712,4 +712,5 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
Length, Fragment).
sufficient_tlsv1_2_crypto_support() ->
- proplists:get_bool(sha256, crypto:algorithms()).
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
diff --git a/lib/ssl/src/tls_record.hrl b/lib/ssl/src/tls_record.hrl
new file mode 100644
index 0000000000..c9350fa137
--- /dev/null
+++ b/lib/ssl/src/tls_record.hrl
@@ -0,0 +1,39 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the TLS-record protocol
+%% see RFC 5246
+%%----------------------------------------------------------------------
+
+-ifndef(tls_record).
+-define(tls_record, true).
+
+-include("ssl_record.hrl"). %% Common TLS and DTLS records and Constantes
+
+%% Used to handle tls_plain_text, tls_compressed and tls_cipher_text
+
+-record(ssl_tls, {
+ type,
+ version,
+ fragment
+ }).
+
+-endif. % -ifdef(tls_record).