aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
authorAndreas Schultz <[email protected]>2012-04-08 03:19:43 +0200
committerIngela Anderton Andin <[email protected]>2012-08-22 14:00:44 +0200
commit5f81b3f94f82107bf830b46ee643787b774d8634 (patch)
tree1206b4291e850ed8969d90d39e438dc25be239aa /lib/ssl
parentd848984efd05314abf2de8da6ddd4ee651f0da35 (diff)
downloadotp-5f81b3f94f82107bf830b46ee643787b774d8634.tar.gz
otp-5f81b3f94f82107bf830b46ee643787b774d8634.tar.bz2
otp-5f81b3f94f82107bf830b46ee643787b774d8634.zip
ssl: Implement and activate PRFs for TLS 1.1 and 1.2
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/src/ssl_handshake.erl25
-rw-r--r--lib/ssl/src/ssl_tls1.erl111
2 files changed, 107 insertions, 29 deletions
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 1759c920cc..1b83293730 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -549,9 +549,10 @@ server_key_exchange_hash(dhe_dss, Value) ->
%%--------------------------------------------------------------------
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)}.
+prf({3,1}, Secret, Label, Seed, WantedLength) ->
+ {ok, ssl_tls1:prf(?MD5SHA, Secret, Label, Seed, WantedLength)};
+prf({3,N}, Secret, Label, Seed, WantedLength) ->
+ {ok, ssl_tls1:prf(?SHA256, Secret, Label, Seed, WantedLength)}.
%%--------------------------------------------------------------------
%%% Internal functions
@@ -1124,7 +1125,12 @@ calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom)
calc_master_secret({3,N}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom)
when N == 1; N == 2 ->
- ssl_tls1:master_secret(?MD5SHA, PremasterSecret, ClientRandom, ServerRandom).
+ ssl_tls1:master_secret(?MD5SHA, PremasterSecret, ClientRandom, ServerRandom);
+
+calc_master_secret({3,N}, PrfAlgo, PremasterSecret, ClientRandom, ServerRandom)
+ when N == 3 ->
+ %% only from TLS 1.2 onwards the selection of a PrfAlgo is supported
+ ssl_tls1:master_secret(PrfAlgo, PremasterSecret, ClientRandom, ServerRandom).
setup_keys({3,0}, _PrfAlgo, MasterSecret,
ServerRandom, ClientRandom, HashSize, KML, EKML, IVS) ->
@@ -1135,13 +1141,22 @@ setup_keys({3,N}, _PrfAlgo, MasterSecret,
ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS)
when N == 1; N == 2 ->
ssl_tls1:setup_keys(N, ?MD5SHA, MasterSecret, ServerRandom, ClientRandom, HashSize,
+ KML, IVS);
+
+setup_keys({3,N}, PrfAlgo, MasterSecret,
+ ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS)
+ when N == 3 ->
+ ssl_tls1:setup_keys(N, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
KML, IVS).
calc_finished({3, 0}, Role, _PrfAlgo, MasterSecret, Handshake) ->
ssl_ssl3:finished(Role, MasterSecret, lists:reverse(Handshake));
calc_finished({3, N}, Role, _PrfAlgo, MasterSecret, Handshake)
when N == 1; N == 2 ->
- ssl_tls1:finished(Role, N, ?MD5SHA, MasterSecret, lists:reverse(Handshake)).
+ ssl_tls1:finished(Role, N, ?MD5SHA, MasterSecret, lists:reverse(Handshake));
+calc_finished({3, N}, Role, PrfAlgo, MasterSecret, Handshake)
+ when N == 3 ->
+ ssl_tls1:finished(Role, N, PrfAlgo, MasterSecret, lists:reverse(Handshake)).
calc_certificate_verify({3, 0}, HashAlgo, MasterSecret, Handshake) ->
ssl_ssl3:certificate_verify(HashAlgo, MasterSecret, lists:reverse(Handshake));
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index dc3d9774c2..9569cef8d1 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -61,6 +61,18 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
SHA = crypto:sha(Handshake),
prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12);
+finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
+ when Version == 3 ->
+ %% RFC 5246 - 7.4.9. Finished
+ %% struct {
+ %% opaque verify_data[12];
+ %% } Finished;
+ %%
+ %% verify_data
+ %% PRF(master_secret, finished_label, Hash(handshake_messages)) [0..11];
+ Hash = crypto:hash(mac_algo(PrfAlgo), Handshake),
+ prf(PrfAlgo, MasterSecret, finished_label(Role), Hash, 12).
+
-spec certificate_verify(OID::tuple(), [binary()]) -> binary().
certificate_verify(?'rsaEncryption', Handshake) ->
@@ -98,29 +110,60 @@ setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize
ClientWriteKey:KeyMatLen/binary, ServerWriteKey:KeyMatLen/binary,
ClientIV:IVSize/binary, ServerIV:IVSize/binary>> = KeyBlock,
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
- ServerWriteKey, ClientIV, ServerIV}.
+ ServerWriteKey, ClientIV, ServerIV};
+
+%% TLS v1.1
+setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
+ KeyMatLen, IVSize)
+ when Version == 2 ->
+ %% RFC 4346 - 6.3. Key calculation
+ %% key_block = PRF(SecurityParameters.master_secret,
+ %% "key expansion",
+ %% SecurityParameters.server_random +
+ %% SecurityParameters.client_random);
+ %% Then the key_block is partitioned as follows:
+ %% client_write_MAC_secret[SecurityParameters.hash_size]
+ %% server_write_MAC_secret[SecurityParameters.hash_size]
+ %% client_write_key[SecurityParameters.key_material_length]
+ %% server_write_key[SecurityParameters.key_material_length]
+ %%
+ %% RFC 4346 is incomplete, the client and server IVs have to
+ %% be generated just like for TLS 1.0
+ WantedLength = 2 * (HashSize + KeyMatLen + IVSize),
+ KeyBlock = prf(?MD5SHA, MasterSecret, "key expansion",
+ [ServerRandom, ClientRandom], WantedLength),
+ <<ClientWriteMacSecret:HashSize/binary,
+ ServerWriteMacSecret:HashSize/binary,
+ ClientWriteKey:KeyMatLen/binary, ServerWriteKey:KeyMatLen/binary,
+ ClientIV:IVSize/binary, ServerIV:IVSize/binary>> = KeyBlock,
+ {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
+ ServerWriteKey, ClientIV, ServerIV};
-%% TLS v1.1 uncomment when supported.
-%% setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, KeyMatLen) ->
-%% %% RFC 4346 - 6.3. Key calculation
-%% %% key_block = PRF(SecurityParameters.master_secret,
-%% %% "key expansion",
-%% %% SecurityParameters.server_random +
-%% %% SecurityParameters.client_random);
-%% %% Then the key_block is partitioned as follows:
-%% %% client_write_MAC_secret[SecurityParameters.hash_size]
-%% %% server_write_MAC_secret[SecurityParameters.hash_size]
-%% %% client_write_key[SecurityParameters.key_material_length]
-%% %% server_write_key[SecurityParameters.key_material_length]
-%% WantedLength = 2 * (HashSize + KeyMatLen),
-%% KeyBlock = prf(MasterSecret, "key expansion",
-%% [ServerRandom, ClientRandom], WantedLength),
-%% <<ClientWriteMacSecret:HashSize/binary,
-%% ServerWriteMacSecret:HashSize/binary,
-%% ClientWriteKey:KeyMatLen/binary, ServerWriteKey:KeyMatLen/binary>>
-%% = KeyBlock,
-%% {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
-%% ServerWriteKey, undefined, undefined}.
+%% TLS v1.2
+setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
+ KeyMatLen, IVSize)
+ when Version == 3 ->
+ %% RFC 5246 - 6.3. Key calculation
+ %% key_block = PRF(SecurityParameters.master_secret,
+ %% "key expansion",
+ %% SecurityParameters.server_random +
+ %% SecurityParameters.client_random);
+ %% Then the key_block is partitioned as follows:
+ %% client_write_MAC_secret[SecurityParameters.hash_size]
+ %% server_write_MAC_secret[SecurityParameters.hash_size]
+ %% client_write_key[SecurityParameters.key_material_length]
+ %% server_write_key[SecurityParameters.key_material_length]
+ %% client_write_IV[SecurityParameters.fixed_iv_length]
+ %% server_write_IV[SecurityParameters.fixed_iv_length]
+ WantedLength = 2 * (HashSize + KeyMatLen + IVSize),
+ KeyBlock = prf(PrfAlgo, MasterSecret, "key expansion",
+ [ServerRandom, ClientRandom], WantedLength),
+ <<ClientWriteMacSecret:HashSize/binary,
+ ServerWriteMacSecret:HashSize/binary,
+ ClientWriteKey:KeyMatLen/binary, ServerWriteKey:KeyMatLen/binary,
+ ClientIV:IVSize/binary, ServerIV:IVSize/binary>> = KeyBlock,
+ {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
+ ServerWriteKey, ClientIV, ServerIV}.
-spec mac_hash(integer(), binary(), integer(), integer(), tls_version(),
integer(), binary()) -> binary().
@@ -166,7 +209,22 @@ hmac_hash(?NULL, _, _) ->
hmac_hash(?MD5, Key, Value) ->
crypto:md5_mac(Key, Value);
hmac_hash(?SHA, Key, Value) ->
- crypto:sha_mac(Key, Value).
+ crypto:sha_mac(Key, Value);
+hmac_hash(?MD5SHA, Key, Value) ->
+ crypto:sha256_mac(Key, Value);
+hmac_hash(?SHA256, Key, Value) ->
+ crypto:sha256_mac(Key, Value);
+hmac_hash(?SHA384, Key, Value) ->
+ crypto:sha384_mac(Key, Value);
+hmac_hash(?SHA512, Key, Value) ->
+ crypto:sha512_mac(Key, Value).
+
+mac_algo(?MD5) -> md5;
+mac_algo(?SHA) -> sha;
+mac_algo(?MD5SHA) -> sha256; %% RFC 5246 defines minimum hash for TLS 1.2
+mac_algo(?SHA256) -> sha256;
+mac_algo(?SHA384) -> sha384;
+mac_algo(?SHA512) -> sha512.
% First, we define a data expansion function, P_hash(secret, data) that
% uses a single hash function to expand a secret and seed into an
@@ -224,7 +282,12 @@ prf(MAC, Secret, Label, Seed, WantedLength)
{S1, S2} = split_secret(Secret),
LS = list_to_binary([Label, Seed]),
crypto:exor(p_hash(S1, LS, WantedLength, ?MD5),
- p_hash(S2, LS, WantedLength, ?SHA)).
+ p_hash(S2, LS, WantedLength, ?SHA));
+
+prf(MAC, Secret, Label, Seed, WantedLength) ->
+ %% PRF(secret, label, seed) = P_SHA256(secret, label + seed);
+ LS = list_to_binary([Label, Seed]),
+ p_hash(Secret, LS, WantedLength, MAC).
%%%% Misc help functions %%%%