aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src/ssl_v3.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src/ssl_v3.erl')
-rw-r--r--lib/ssl/src/ssl_v3.erl203
1 files changed, 203 insertions, 0 deletions
diff --git a/lib/ssl/src/ssl_v3.erl b/lib/ssl/src/ssl_v3.erl
new file mode 100644
index 0000000000..d477b3df81
--- /dev/null
+++ b/lib/ssl/src/ssl_v3.erl
@@ -0,0 +1,203 @@
+%%
+%% %CopyrightBegin%
+%%
+%% 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
+%% 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: Handles sslv3 encryption.
+%%----------------------------------------------------------------------
+
+-module(ssl_v3).
+
+-include("ssl_cipher.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_record.hrl"). % MD5 and SHA
+
+-export([master_secret/3, finished/3, certificate_verify/3,
+ mac_hash/6, setup_keys/7,
+ suites/0]).
+-compile(inline).
+
+%%====================================================================
+%% Internal application API
+%%====================================================================
+
+-spec master_secret(binary(), binary(), binary()) -> binary().
+
+master_secret(PremasterSecret, ClientRandom, ServerRandom) ->
+ %% draft-ietf-tls-ssl-version3-00 - 6.2.2
+ %% key_block =
+ %% MD5(master_secret + SHA(`A' + master_secret +
+ %% ServerHello.random +
+ %% ClientHello.random)) +
+ %% MD5(master_secret + SHA(`BB' + master_secret +
+ %% ServerHello.random +
+ %% ClientHello.random)) +
+ %% MD5(master_secret + SHA(`CCC' + master_secret +
+ %% ServerHello.random +
+ %% ClientHello.random)) + [...];
+ Block = generate_keyblock(PremasterSecret, ClientRandom, ServerRandom, 48),
+ Block.
+
+-spec finished(client | server, binary(), [binary()]) -> binary().
+
+finished(Role, MasterSecret, Handshake) ->
+ %% draft-ietf-tls-ssl-version3-00 - 5.6.9 Finished
+ %% struct {
+ %% opaque md5_hash[16];
+ %% opaque sha_hash[20];
+ %% } Finished;
+ %%
+ %% md5_hash MD5(master_secret + pad2 +
+ %% MD5(handshake_messages + Sender +
+ %% master_secret + pad1));
+ %% sha_hash SHA(master_secret + pad2 +
+ %% SHA(handshake_messages + Sender +
+ %% master_secret + pad1));
+ Sender = get_sender(Role),
+ MD5 = handshake_hash(?MD5, MasterSecret, Sender, Handshake),
+ SHA = handshake_hash(?SHA, MasterSecret, Sender, Handshake),
+ <<MD5/binary, SHA/binary>>.
+
+-spec certificate_verify(md5sha | sha, binary(), [binary()]) -> binary().
+
+certificate_verify(md5sha, MasterSecret, Handshake) ->
+ %% md5_hash
+ %% MD5(master_secret + pad_2 +
+ %% MD5(handshake_messages + master_secret + pad_1));
+ %% sha_hash
+ %% SHA(master_secret + pad_2 +
+ %% SHA(handshake_messages + master_secret + pad_1));
+
+ MD5 = handshake_hash(?MD5, MasterSecret, undefined, Handshake),
+ SHA = handshake_hash(?SHA, MasterSecret, undefined, Handshake),
+ <<MD5/binary, SHA/binary>>;
+
+certificate_verify(sha, MasterSecret, Handshake) ->
+ %% sha_hash
+ %% SHA(master_secret + pad_2 +
+ %% SHA(handshake_messages + master_secret + pad_1));
+
+ handshake_hash(?SHA, MasterSecret, undefined, Handshake).
+
+-spec mac_hash(integer(), binary(), integer(), integer(), integer(), binary()) -> binary().
+
+mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) ->
+ %% draft-ietf-tls-ssl-version3-00 - 5.2.3.1
+ %% hash(MAC_write_secret + pad_2 +
+ %% hash(MAC_write_secret + pad_1 + seq_num +
+ %% SSLCompressed.type + SSLCompressed.length +
+ %% SSLCompressed.fragment));
+ Mac = mac_hash(Method, Mac_write_secret,
+ [<<?UINT64(Seq_num), ?BYTE(Type),
+ ?UINT16(Length)>>, Fragment]),
+ Mac.
+
+-spec setup_keys(binary(), binary(), binary(),
+ integer(), integer(), term(), integer()) ->
+ {binary(), binary(), binary(),
+ binary(), binary(), binary()}.
+
+setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
+ KeyBlock = generate_keyblock(MasterSecret, ServerRandom, ClientRandom,
+ 2*(HS+KML+IVS)),
+ %% draft-ietf-tls-ssl-version3-00 - 6.2.2
+ %% The key_block is partitioned as follows.
+ %% client_write_MAC_secret[CipherSpec.hash_size]
+ %% server_write_MAC_secret[CipherSpec.hash_size]
+ %% client_write_key[CipherSpec.key_material]
+ %% server_write_key[CipherSpec.key_material]
+ %% client_write_IV[CipherSpec.IV_size] /* non-export ciphers */
+ %% server_write_IV[CipherSpec.IV_size] /* non-export ciphers */
+ <<ClientWriteMacSecret:HS/binary, ServerWriteMacSecret:HS/binary,
+ ClientWriteKey:KML/binary, ServerWriteKey:KML/binary,
+ ClientIV:IVS/binary, ServerIV:IVS/binary>> = KeyBlock,
+ {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
+ ServerWriteKey, ClientIV, ServerIV}.
+
+-spec suites() -> [cipher_suite()].
+
+suites() ->
+ [
+ ?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_IDEA_CBC_SHA,
+ ?TLS_RSA_WITH_RC4_128_SHA,
+ ?TLS_RSA_WITH_RC4_128_MD5,
+ ?TLS_RSA_WITH_DES_CBC_SHA
+ ].
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
+hash(?MD5, Data) ->
+ crypto:hash(md5, Data);
+hash(?SHA, Data) ->
+ crypto:hash(sha, Data).
+
+%%pad_1(?NULL) ->
+%% "";
+pad_1(?MD5) ->
+ <<"666666666666666666666666666666666666666666666666">>;
+pad_1(?SHA) ->
+ <<"6666666666666666666666666666666666666666">>.
+%%pad_2(?NULL) ->
+%% "";
+pad_2(?MD5) ->
+ <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"
+ "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>;
+pad_2(?SHA) ->
+ <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"
+ "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>.
+
+mac_hash(?NULL, _Secret, _Data) ->
+ <<>>;
+mac_hash(Method, Secret, Data) ->
+ InnerHash = hash(Method, [Secret, pad_1(Method), Data]),
+ hash(Method, [Secret, pad_2(Method), InnerHash]).
+
+handshake_hash(Method, MasterSecret, undefined, Handshake) ->
+ InnerHash = hash(Method, [Handshake, MasterSecret, pad_1(Method)]),
+ hash(Method, [MasterSecret, pad_2(Method), InnerHash]);
+handshake_hash(Method, MasterSecret, Sender, Handshake) ->
+ InnerHash = hash(Method, [Handshake, Sender, MasterSecret, pad_1(Method)]),
+ hash(Method, [MasterSecret, pad_2(Method), InnerHash]).
+
+get_sender(client) -> "CLNT";
+get_sender(server) -> "SRVR".
+
+generate_keyblock(MasterSecret, ServerRandom, ClientRandom, WantedLength) ->
+ gen(MasterSecret, [MasterSecret, ServerRandom, ClientRandom],
+ WantedLength, 0, $A, 1, []).
+
+gen(_Secret, _All, Wanted, Len, _C, _N, Acc) when Wanted =< Len ->
+ <<Block:Wanted/binary, _/binary>> = list_to_binary(lists:reverse(Acc)),
+ Block;
+gen(Secret, All, Wanted, Len, C, N, Acc) ->
+ Prefix = lists:duplicate(N, C),
+ SHA = crypto:hash(sha, [Prefix, All]),
+ MD5 = crypto:hash(md5, [Secret, SHA]),
+ gen(Secret, All, Wanted, Len + 16, C+1, N+1, [MD5 | Acc]).