diff options
Diffstat (limited to 'lib/ssl/src/ssl_ssl3.erl')
-rw-r--r-- | lib/ssl/src/ssl_ssl3.erl | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl new file mode 100644 index 0000000000..ab29ac64df --- /dev/null +++ b/lib/ssl/src/ssl_ssl3.erl @@ -0,0 +1,286 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. 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_ssl3). + +-include("ssl_cipher.hrl"). +-include("ssl_debug.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/8, + suites/0]). +-compile(inline). + +%%==================================================================== +%% Internal application API +%%==================================================================== + +master_secret(PremasterSecret, ClientRandom, ServerRandom) -> + ?DBG_HEX(PremasterSecret), + ?DBG_HEX(ClientRandom), + ?DBG_HEX(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)) + [...]; + B = generate_keyblock(PremasterSecret, ClientRandom, ServerRandom, 48), + ?DBG_HEX(B), + B. + +finished(Role, MasterSecret, {MD5Hash, SHAHash}) -> + %% 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, MD5Hash), + SHA = handshake_hash(?SHA, MasterSecret, Sender, SHAHash), + <<MD5/binary, SHA/binary>>. + +certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash}) + when Algorithm == rsa; Algorithm == dh_rsa; Algorithm == dhe_rsa -> + %% 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, MD5Hash), + SHA = handshake_hash(?SHA, MasterSecret, undefined, SHAHash), + <<MD5/binary, SHA/binary>>; + +certificate_verify(Algorithm, MasterSecret, {_, SHAHash}) + when Algorithm == dh_dss; Algorithm == dhe_dss -> + %% sha_hash + %% SHA(master_secret + pad_2 + + %% SHA(handshake_messages + master_secret + pad_1)); + handshake_hash(?SHA, MasterSecret, undefined, SHAHash). + +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)); + case Method of + ?NULL -> ok; + _ -> + ?DBG_HEX(Mac_write_secret), + ?DBG_HEX(hash(Method, Fragment)), + ok + end, + Mac = mac_hash(Method, Mac_write_secret, + [<<?UINT64(Seq_num), ?BYTE(Type), + ?UINT16(Length)>>, Fragment]), + ?DBG_HEX(Mac), + Mac. + +setup_keys(Exportable, MasterSecret, ServerRandom, ClientRandom, + HS, KML, _EKML, IVS) + when Exportable == no_export; Exportable == ignore -> + 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, + ?DBG_HEX(ClientWriteMacSecret), + ?DBG_HEX(ServerWriteMacSecret), + ?DBG_HEX(ClientWriteKey), + ?DBG_HEX(ServerWriteKey), + ?DBG_HEX(ClientIV), + ?DBG_HEX(ServerIV), + {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, + ServerWriteKey, ClientIV, ServerIV}; + +setup_keys(export, MasterSecret, ServerRandom, ClientRandom, + HS, KML, EKML, IVS) -> + KeyBlock = generate_keyblock(MasterSecret, ServerRandom, ClientRandom, + 2*(HS+KML)), + %% draft-ietf-tls-ssl-version3-00 - 6.2.2 + %% Exportable encryption algorithms (for which + %% CipherSpec.is_exportable is true) require additional processing as + %% follows to derive their final write keys: + + %% final_client_write_key = MD5(client_write_key + + %% ClientHello.random + + %% ServerHello.random); + %% final_server_write_key = MD5(server_write_key + + %% ServerHello.random + + %% ClientHello.random); + + %% Exportable encryption algorithms derive their IVs from the random + %% messages: + %% client_write_IV = MD5(ClientHello.random + ServerHello.random); + %% server_write_IV = MD5(ServerHello.random + ClientHello.random); + + <<ClientWriteMacSecret:HS/binary, ServerWriteMacSecret:HS/binary, + ClientWriteKey:KML/binary, ServerWriteKey:KML/binary>> = KeyBlock, + <<ClientIV:IVS/binary, _/binary>> = + hash(?MD5, [ClientRandom, ServerRandom]), + <<ServerIV:IVS/binary, _/binary>> = + hash(?MD5, [ServerRandom, ClientRandom]), + <<FinalClientWriteKey:EKML/binary, _/binary>> = + hash(?MD5, [ClientWriteKey, ClientRandom, ServerRandom]), + <<FinalServerWriteKey:EKML/binary, _/binary>> = + hash(?MD5, [ServerWriteKey, ServerRandom, ClientRandom]), + ?DBG_HEX(ClientWriteMacSecret), + ?DBG_HEX(ServerWriteMacSecret), + ?DBG_HEX(FinalClientWriteKey), + ?DBG_HEX(FinalServerWriteKey), + ?DBG_HEX(ClientIV), + ?DBG_HEX(ServerIV), + {ClientWriteMacSecret, ServerWriteMacSecret, FinalClientWriteKey, + FinalServerWriteKey, ClientIV, ServerIV}. + +suites() -> + [ + %% TODO: uncomment when supported + %% ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + %% ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + %% TODO: Funkar inte, borde: ?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_DHE_DSS_WITH_RC4_128_SHA, TODO: Support this? + %% ?TLS_RSA_WITH_IDEA_CBC_SHA, Not supported: in later openssl version than OTP requires + + ?TLS_RSA_WITH_RC4_128_SHA, + ?TLS_RSA_WITH_RC4_128_MD5, + %%?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5, + %%?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5, + %%?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, + %%?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, + %%?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, + %%?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, + %%?TLS_DHE_DSS_WITH_RC4_128_SHA, + + ?TLS_RSA_WITH_DES_CBC_SHA + %% ?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, + %% ?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, + %% ?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, + %%?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, + %%?TLS_RSA_EXPORT_WITH_RC4_40_MD5 + ]. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + +hash(?MD5, Data) -> + crypto:md5(Data); +hash(?SHA, Data) -> + crypto:sha(Data). + +hash_update(?MD5, Context, Data) -> + crypto:md5_update(Context, Data); +hash_update(?SHA, Context, Data) -> + crypto:sha_update(Context, Data). + +hash_final(?MD5, Context) -> + crypto:md5_final(Context); +hash_final(?SHA, Context) -> + crypto:sha_final(Context). + +%%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, HandshakeHash, Extra) -> + HSH = hash_update(Method, HandshakeHash, Extra), + hash_final(Method, HSH). + +handshake_hash(Method, MasterSecret, undefined, HandshakeHash) -> + InnerHash = + handshake_hash(Method, HandshakeHash, + [MasterSecret, pad_1(Method)]), + hash(Method, [MasterSecret, pad_2(Method), InnerHash]); +handshake_hash(Method, MasterSecret, Sender, HandshakeHash) -> + InnerHash = + handshake_hash(Method, HandshakeHash, + [Sender, MasterSecret, pad_1(Method)]), + hash(Method, [MasterSecret, pad_2(Method), InnerHash]). + +get_sender(client) -> "CLNT"; +get_sender(server) -> "SRVR"; +get_sender(none) -> "". + +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:sha([Prefix, All]), + MD5 = crypto:md5([Secret, SHA]), + gen(Secret, All, Wanted, Len + 16, C+1, N+1, [MD5 | Acc]). |