aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src
diff options
context:
space:
mode:
authorAndreas Schultz <[email protected]>2012-02-24 13:47:13 +0100
committerGustav Simonsson <[email protected]>2012-03-05 12:14:52 +0100
commit89ae746305215c5dd077441ba796ff37b03fdaa3 (patch)
treefd425ee7536d82107ce53ebdf298d91e2c79ed9e /lib/ssl/src
parent1bc4f4c35876a8dcccad66129e68f602751f6e36 (diff)
downloadotp-89ae746305215c5dd077441ba796ff37b03fdaa3.tar.gz
otp-89ae746305215c5dd077441ba796ff37b03fdaa3.tar.bz2
otp-89ae746305215c5dd077441ba796ff37b03fdaa3.zip
Some protocols (e.g. EAP-PEAP, EAP-TLS, EAP-TTLS) that use TLS as
transport layer need to generate additional application specific key material. One way to generate such material is to use the TLS PRF and key material from the TLS session itself. This change makes it possible to use a TLS sessions PRF either with the session internal or caller supplied key material to generate additional key material.
Diffstat (limited to 'lib/ssl/src')
-rw-r--r--lib/ssl/src/ssl.erl15
-rw-r--r--lib/ssl/src/ssl_connection.erl39
-rw-r--r--lib/ssl/src/ssl_handshake.erl14
-rw-r--r--lib/ssl/src/ssl_tls1.erl2
4 files changed, 65 insertions, 5 deletions
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index d0693445e0..1048583eca 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -30,7 +30,7 @@
controlling_process/2, listen/2, pid/1, 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]).
+ renegotiate/1, prf/5]).
-deprecated({pid, 1, next_major_release}).
@@ -67,7 +67,7 @@
-type ssl_imp() :: new | old.
-type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(), ClosedTag::atom()}}.
-
+-type prf_random() :: client_random | server_random.
%%--------------------------------------------------------------------
-spec start() -> ok | {error, reason()}.
@@ -414,6 +414,17 @@ versions() ->
renegotiate(#sslsocket{pid = Pid, fd = new_ssl}) ->
ssl_connection:renegotiation(Pid).
+%%--------------------------------------------------------------------
+-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, fd = new_ssl},
+ Secret, Label, Seed, WantedLength) ->
+ ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength).
+
%%---------------------------------------------------------------
-spec format_error({error, term()}) -> list().
%%
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 28dd0c85d0..59133dccf0 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -40,7 +40,8 @@
-export([send/2, recv/3, connect/7, ssl_accept/6, handshake/2,
socket_control/3, close/1, shutdown/2,
new_user/2, get_opts/2, set_opts/2, info/1, session_info/1,
- peer_certificate/1, sockname/1, peername/1, renegotiation/1]).
+ peer_certificate/1, sockname/1, peername/1, renegotiation/1,
+ prf/5]).
%% Called by ssl_connection_sup
-export([start_link/7]).
@@ -273,6 +274,16 @@ peer_certificate(ConnectionPid) ->
renegotiation(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, renegotiate).
+%%--------------------------------------------------------------------
+-spec prf(pid(), binary() | 'master_secret', binary(),
+ binary() | ssl:prf_secret(), non_neg_integer()) ->
+ {ok, binary()} | {error, reason()} | {'EXIT', term()}.
+%%
+%% Description: use a ssl sessions TLS PRF to generate key material
+%%--------------------------------------------------------------------
+prf(ConnectionPid, Secret, Label, Seed, WantedLength) ->
+ sync_send_all_state_event(ConnectionPid, {prf, Secret, Label, Seed, WantedLength}).
+
%%====================================================================
%% ssl_connection_sup API
%%====================================================================
@@ -868,6 +879,32 @@ handle_sync_event(renegotiate, From, connection, State) ->
handle_sync_event(renegotiate, _, StateName, State) ->
{reply, {error, already_renegotiating}, StateName, State, get_timeout(State)};
+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),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{master_secret = MasterSecret,
+ client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Reply = try
+ SecretToUse = case Secret of
+ _ when is_binary(Secret) -> Secret;
+ master_secret -> MasterSecret
+ end,
+ SeedToUse = lists:reverse(
+ lists:foldl(fun(X, Acc) when is_binary(X) -> [X|Acc];
+ (client_random, Acc) -> [ClientRandom|Acc];
+ (server_random, Acc) -> [ServerRandom|Acc]
+ end, [], Seed)),
+ ssl_handshake:prf(Version, SecretToUse, Label, SeedToUse, WantedLength)
+ catch
+ exit:_ -> {error, badarg};
+ error:Reason -> {error, Reason}
+ end,
+ {reply, Reply, StateName, State, get_timeout(State)};
+
handle_sync_event(info, _, StateName,
#state{negotiated_version = Version,
session = #session{cipher_suite = Suite}} = State) ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 542033e6ce..ef60cac6df 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -37,7 +37,7 @@
finished/4, verify_connection/5, get_tls_handshake/2,
decode_client_key/3, server_hello_done/0,
encode_handshake/2, init_hashes/0, update_hashes/2,
- decrypt_premaster_secret/2]).
+ decrypt_premaster_secret/2, prf/5]).
-export([dec_hello_extensions/2]).
@@ -543,6 +543,18 @@ server_key_exchange_hash(dhe_dss, Value) ->
crypto:sha(Value).
%%--------------------------------------------------------------------
+-spec prf(tls_version(), binary(), binary(), binary(), non_neg_integer()) ->
+ {ok, binary()} | {error, undefined}.
+%%
+%% Description: use the TLS PRF to generate key material
+%%--------------------------------------------------------------------
+prf({3,0}, _, _, _, _) ->
+ {error, undefined};
+prf({3,N}, Secret, Label, Seed, WantedLength)
+ when N == 1; N == 2 ->
+ {ok, ssl_tls1:prf(Secret, Label, Seed, WantedLength)}.
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length),
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index 5f9850c386..7351f34b61 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -29,7 +29,7 @@
-include("ssl_record.hrl").
-export([master_secret/3, finished/3, certificate_verify/2, mac_hash/7,
- setup_keys/6, suites/0]).
+ setup_keys/6, suites/0, prf/4]).
%%====================================================================
%% Internal application API