aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src/ssl_tls1.erl
diff options
context:
space:
mode:
authorIngela Anderton Andin <[email protected]>2013-06-18 12:30:38 +0200
committerIngela Anderton Andin <[email protected]>2013-09-10 09:37:29 +0200
commitb9a31f24053c84d9a7ffa4281bc11f47b3be5905 (patch)
treee0698a95d56b1fd6070d916033cd07f098d3b5ed /lib/ssl/src/ssl_tls1.erl
parentfb6ac178ac437fcc04f1675df75b0583c1d24ad7 (diff)
downloadotp-b9a31f24053c84d9a7ffa4281bc11f47b3be5905.tar.gz
otp-b9a31f24053c84d9a7ffa4281bc11f47b3be5905.tar.bz2
otp-b9a31f24053c84d9a7ffa4281bc11f47b3be5905.zip
ssl: DTLS record handling
Also refactor so that TLS and DTLS can have common functions when possible.
Diffstat (limited to 'lib/ssl/src/ssl_tls1.erl')
-rw-r--r--lib/ssl/src/ssl_tls1.erl432
1 files changed, 0 insertions, 432 deletions
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
deleted file mode 100644
index 8ab66d0627..0000000000
--- a/lib/ssl/src/ssl_tls1.erl
+++ /dev/null
@@ -1,432 +0,0 @@
-%%
-%% %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 tls1 encryption.
-%%----------------------------------------------------------------------
-
--module(ssl_tls1).
-
--include("ssl_cipher.hrl").
--include("ssl_internal.hrl").
--include("ssl_record.hrl").
-
--export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7,
- setup_keys/8, suites/1, prf/5,
- ecc_curves/1, oid_to_enum/1, enum_to_oid/1]).
-
-%%====================================================================
-%% Internal application API
-%%====================================================================
-
--spec master_secret(integer(), binary(), binary(), binary()) -> binary().
-
-master_secret(PrfAlgo, PreMasterSecret, ClientRandom, ServerRandom) ->
- %% RFC 2246 & 4346 && RFC 5246 - 8.1 %% master_secret = PRF(pre_master_secret,
- %% "master secret", ClientHello.random +
- %% ServerHello.random)[0..47];
-
- prf(PrfAlgo, PreMasterSecret, <<"master secret">>,
- [ClientRandom, ServerRandom], 48).
-
--spec finished(client | server, integer(), integer(), binary(), [binary()]) -> binary().
-
-finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
- when Version == 1; Version == 2; PrfAlgo == ?MD5SHA ->
- %% RFC 2246 & 4346 - 7.4.9. Finished
- %% struct {
- %% opaque verify_data[12];
- %% } Finished;
- %%
- %% verify_data
- %% PRF(master_secret, finished_label, MD5(handshake_messages) +
- %% SHA-1(handshake_messages)) [0..11];
- MD5 = crypto:hash(md5, Handshake),
- SHA = crypto:hash(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(md5sha | sha, integer(), [binary()]) -> binary().
-
-certificate_verify(md5sha, _Version, Handshake) ->
- MD5 = crypto:hash(md5, Handshake),
- SHA = crypto:hash(sha, Handshake),
- <<MD5/binary, SHA/binary>>;
-
-certificate_verify(HashAlgo, _Version, Handshake) ->
- crypto:hash(HashAlgo, Handshake).
-
--spec setup_keys(integer(), integer(), binary(), binary(), binary(), integer(),
- integer(), integer()) -> {binary(), binary(), binary(),
- binary(), binary(), binary()}.
-
-setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
- KeyMatLen, IVSize)
- when Version == 1 ->
- %% RFC 2246 - 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.IV_size]
- %% server_write_IV[SecurityParameters.IV_size]
- 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
-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.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().
-
-mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
- Length, Fragment) ->
- %% RFC 2246 & 4346 - 6.2.3.1.
- %% HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
- %% TLSCompressed.version + TLSCompressed.length +
- %% TLSCompressed.fragment));
- Mac = hmac_hash(Method, Mac_write_secret,
- [<<?UINT64(Seq_num), ?BYTE(Type),
- ?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>,
- Fragment]),
- Mac.
-
--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,
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
- ?TLS_RSA_WITH_AES_256_CBC_SHA,
-
- ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_RSA_WITH_AES_128_CBC_SHA,
-
- ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
- ?TLS_RSA_WITH_RC4_128_SHA,
- ?TLS_RSA_WITH_RC4_128_MD5,
- ?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
- ];
-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
- ].
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-%%%% HMAC and the Pseudorandom Functions RFC 2246 & 4346 - 5.%%%%
-hmac_hash(?NULL, _, _) ->
- <<>>;
-hmac_hash(Alg, Key, Value) ->
- crypto:hmac(mac_algo(Alg), Key, Value).
-
-mac_algo(?MD5) -> md5;
-mac_algo(?SHA) -> sha;
-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
-% arbitrary quantity of output:
-%% P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
-%% HMAC_hash(secret, A(2) + seed) +
-%% HMAC_hash(secret, A(3) + seed) + ...
-
-p_hash(Secret, Seed, WantedLength, Method) ->
- p_hash(Secret, Seed, WantedLength, Method, 0, []).
-
-p_hash(_Secret, _Seed, WantedLength, _Method, _N, [])
- when WantedLength =< 0 ->
- [];
-p_hash(_Secret, _Seed, WantedLength, _Method, _N, [Last | Acc])
- when WantedLength =< 0 ->
- Keep = byte_size(Last) + WantedLength,
- <<B:Keep/binary, _/binary>> = Last,
- list_to_binary(lists:reverse(Acc, [B]));
-p_hash(Secret, Seed, WantedLength, Method, N, Acc) ->
- N1 = N+1,
- Bin = hmac_hash(Method, Secret, [a(N1, Secret, Seed, Method), Seed]),
- p_hash(Secret, Seed, WantedLength - byte_size(Bin), Method, N1, [Bin|Acc]).
-
-
-%% ... Where A(0) = seed
-%% A(i) = HMAC_hash(secret, A(i-1))
-%% a(0, _Secret, Seed, _Method) ->
-%% Seed.
-%% a(N, Secret, Seed, Method) ->
-%% hmac_hash(Method, Secret, a(N-1, Secret, Seed, Method)).
-a(0, _Secret, Seed, _Method) ->
- Seed;
-a(N, Secret, Seed0, Method) ->
- Seed = hmac_hash(Method, Secret, Seed0),
- a(N-1, Secret, Seed, Method).
-
-split_secret(BinSecret) ->
- %% L_S = length in bytes of secret;
- %% L_S1 = L_S2 = ceil(L_S / 2);
- %% The secret is partitioned into two halves (with the possibility of
- %% one shared byte) as described above, S1 taking the first L_S1 bytes,
- %% and S2 the last L_S2 bytes.
- Length = byte_size(BinSecret),
- Div = Length div 2,
- EvenLength = Length - Div,
- <<Secret1:EvenLength/binary, _/binary>> = BinSecret,
- <<_:Div/binary, Secret2:EvenLength/binary>> = BinSecret,
- {Secret1, Secret2}.
-
-prf(?MD5SHA, Secret, Label, Seed, WantedLength) ->
- %% PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
- %% P_SHA-1(S2, label + seed);
- {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));
-
-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 %%%%
-
-finished_label(client) ->
- <<"client finished">>;
-finished_label(server) ->
- <<"server finished">>.
-
-%% list ECC curves in prefered order
-ecc_curves(_Minor) ->
- [?sect571r1,?sect571k1,?secp521r1,?sect409k1,?sect409r1,
- ?secp384r1,?sect283k1,?sect283r1,?secp256k1,?secp256r1,
- ?sect239k1,?sect233k1,?sect233r1,?secp224k1,?secp224r1,
- ?sect193r1,?sect193r2,?secp192k1,?secp192r1,?sect163k1,
- ?sect163r1,?sect163r2,?secp160k1,?secp160r1,?secp160r2].
-
-%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005)
-oid_to_enum(?sect163k1) -> 1;
-oid_to_enum(?sect163r1) -> 2;
-oid_to_enum(?sect163r2) -> 3;
-oid_to_enum(?sect193r1) -> 4;
-oid_to_enum(?sect193r2) -> 5;
-oid_to_enum(?sect233k1) -> 6;
-oid_to_enum(?sect233r1) -> 7;
-oid_to_enum(?sect239k1) -> 8;
-oid_to_enum(?sect283k1) -> 9;
-oid_to_enum(?sect283r1) -> 10;
-oid_to_enum(?sect409k1) -> 11;
-oid_to_enum(?sect409r1) -> 12;
-oid_to_enum(?sect571k1) -> 13;
-oid_to_enum(?sect571r1) -> 14;
-oid_to_enum(?secp160k1) -> 15;
-oid_to_enum(?secp160r1) -> 16;
-oid_to_enum(?secp160r2) -> 17;
-oid_to_enum(?secp192k1) -> 18;
-oid_to_enum(?secp192r1) -> 19;
-oid_to_enum(?secp224k1) -> 20;
-oid_to_enum(?secp224r1) -> 21;
-oid_to_enum(?secp256k1) -> 22;
-oid_to_enum(?secp256r1) -> 23;
-oid_to_enum(?secp384r1) -> 24;
-oid_to_enum(?secp521r1) -> 25.
-
-enum_to_oid(1) -> ?sect163k1;
-enum_to_oid(2) -> ?sect163r1;
-enum_to_oid(3) -> ?sect163r2;
-enum_to_oid(4) -> ?sect193r1;
-enum_to_oid(5) -> ?sect193r2;
-enum_to_oid(6) -> ?sect233k1;
-enum_to_oid(7) -> ?sect233r1;
-enum_to_oid(8) -> ?sect239k1;
-enum_to_oid(9) -> ?sect283k1;
-enum_to_oid(10) -> ?sect283r1;
-enum_to_oid(11) -> ?sect409k1;
-enum_to_oid(12) -> ?sect409r1;
-enum_to_oid(13) -> ?sect571k1;
-enum_to_oid(14) -> ?sect571r1;
-enum_to_oid(15) -> ?secp160k1;
-enum_to_oid(16) -> ?secp160r1;
-enum_to_oid(17) -> ?secp160r2;
-enum_to_oid(18) -> ?secp192k1;
-enum_to_oid(19) -> ?secp192r1;
-enum_to_oid(20) -> ?secp224k1;
-enum_to_oid(21) -> ?secp224r1;
-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)).