diff options
Diffstat (limited to 'lib/ssl/src')
| -rw-r--r-- | lib/ssl/src/dtls_record.erl | 62 | ||||
| -rw-r--r-- | lib/ssl/src/ssl.erl | 4 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 449 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_cipher.hrl | 96 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_handshake.erl | 5 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_manager.erl | 109 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_record.erl | 40 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_record.hrl | 5 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_session_cache.erl | 10 | ||||
| -rw-r--r-- | lib/ssl/src/tls_record.erl | 62 | ||||
| -rw-r--r-- | lib/ssl/src/tls_v1.erl | 25 | 
11 files changed, 777 insertions, 90 deletions
| diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl index a7bbb6bc40..c0776e822b 100644 --- a/lib/ssl/src/dtls_record.erl +++ b/lib/ssl/src/dtls_record.erl @@ -120,6 +120,26 @@ get_dtls_records_aux(Data, Acc) ->      end.  encode_plain_text(Type, Version, Data, +		  #connection_states{current_write = +					 #connection_state{ +					    epoch = Epoch, +					    sequence_number = Seq, +					    compression_state=CompS0, +					    security_parameters= +						#security_parameters{ +						   cipher_type = ?AEAD, +						   compression_algorithm=CompAlg} +					   }= WriteState0} = ConnectionStates) -> +    {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0), +    WriteState1 = WriteState0#connection_state{compression_state = CompS1}, +    AAD = calc_aad(Type, Version, Epoch, Seq), +    {CipherFragment, WriteState} = ssl_record:cipher_aead(dtls_v1:corresponding_tls_version(Version), +							  Comp, WriteState1, AAD), +    CipherText = encode_tls_cipher_text(Type, Version, Epoch, Seq, CipherFragment), +    {CipherText, ConnectionStates#connection_states{current_write = +							WriteState#connection_state{sequence_number = Seq +1}}}; + +encode_plain_text(Type, Version, Data,  		  #connection_states{current_write=#connection_state{  						      epoch = Epoch,  						      sequence_number = Seq, @@ -141,16 +161,44 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,  			    sequence_number = Seq,  			    fragment = CipherFragment} = CipherText,  		   #connection_states{current_read = -					  #connection_state{compression_state = CompressionS0, -							    security_parameters = SecParams} = ReadState0} -		   = ConnnectionStates0) -> -    CompressAlg = SecParams#security_parameters.compression_algorithm, +					  #connection_state{ +					     compression_state = CompressionS0, +					     security_parameters= +						 #security_parameters{ +						    cipher_type = ?AEAD, +						    compression_algorithm=CompAlg} +					    } = ReadState0}= ConnnectionStates0) -> +    AAD = calc_aad(Type, Version, Epoch, Seq), +    case ssl_record:decipher_aead(dtls_v1:corresponding_tls_version(Version), +				  CipherFragment, ReadState0, AAD) of +	{PlainFragment, ReadState1} -> +	    {Plain, CompressionS1} = ssl_record:uncompress(CompAlg, +							   PlainFragment, CompressionS0), +	    ConnnectionStates = ConnnectionStates0#connection_states{ +				  current_read = ReadState1#connection_state{ +						   compression_state = CompressionS1}}, +	    {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates}; +	#alert{} = Alert -> +	    Alert +    end; + +decode_cipher_text(#ssl_tls{type = Type, version = Version, +			    epoch = Epoch, +			    sequence_number = Seq, +			    fragment = CipherFragment} = CipherText, +		   #connection_states{current_read = +					  #connection_state{ +					     compression_state = CompressionS0, +					     security_parameters= +						 #security_parameters{ +						    compression_algorithm=CompAlg} +					    } = ReadState0}= ConnnectionStates0) ->      {PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),  							   CipherFragment, ReadState0),      MacHash = calc_mac_hash(ReadState1, Type, Version, Epoch, Seq, PlainFragment),      case ssl_record:is_correct_mac(Mac, MacHash) of  	true -> -	    {Plain, CompressionS1} = ssl_record:uncompress(CompressAlg, +	    {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,  							   PlainFragment, CompressionS0),  	    ConnnectionStates = ConnnectionStates0#connection_states{  				  current_read = ReadState1#connection_state{ @@ -368,3 +416,7 @@ calc_mac_hash(#connection_state{mac_secret = MacSecret,  mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->      dtls_v1:mac_hash(Version, MacAlg, MacSecret, SeqNo, Type,  		     Length, Fragment). + +calc_aad(Type, {MajVer, MinVer}, Epoch, SeqNo) -> +    NewSeq = (Epoch bsl 48) + SeqNo, +    <<NewSeq:64/integer, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>. diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index b4bea25942..dcba69a65e 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -354,7 +354,7 @@ cipher_suites(openssl) ->  cipher_suites(all) ->      Version = tls_record:highest_protocol_version([]),      Supported = ssl_cipher:all_suites(Version) -	++ ssl_cipher:anonymous_suites() +	++ ssl_cipher:anonymous_suites(Version)  	++ ssl_cipher:psk_suites(Version)  	++ ssl_cipher:srp_suites(),      ssl_cipher:filter_suites([suite_definition(S) || S <- Supported]). @@ -953,7 +953,7 @@ binary_cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->  binary_cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->      All = ssl_cipher:suites(Version) -	++ ssl_cipher:anonymous_suites() +	++ ssl_cipher:anonymous_suites(Version)  	++ ssl_cipher:psk_suites(Version)  	++ ssl_cipher:srp_suites(),      case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, All)] of diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 72467ea2a0..e1d89c149e 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -33,9 +33,9 @@  -include_lib("public_key/include/public_key.hrl").  -export([security_parameters/2, security_parameters/3, suite_definition/1, -	 decipher/5, cipher/5, +	 cipher_init/3, decipher/5, cipher/5, decipher_aead/6, cipher_aead/6,  	 suite/1, suites/1, all_suites/1,  -	 ec_keyed_suites/0, anonymous_suites/0, psk_suites/1, srp_suites/0, +	 ec_keyed_suites/0, anonymous_suites/1, psk_suites/1, srp_suites/0,  	 openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,  	 hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2]). @@ -44,7 +44,7 @@  	      key_algo/0]).  -type cipher()            :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'  -			   | aes_128_cbc |  aes_256_cbc. +			   | aes_128_cbc |  aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305.  -type hash()              :: null | sha | md5 | sha224 | sha256 | sha384 | sha512.  -type key_algo()          :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.  -type erl_cipher_suite()  :: {key_algo(), cipher(), hash()}. @@ -88,20 +88,32 @@ security_parameters(Version, CipherSuite, SecParams) ->        hash_size = hash_size(Hash)}.  %%-------------------------------------------------------------------- +-spec cipher_init(cipher_enum(), binary(), binary()) -> #cipher_state{}. +%% +%% Description: Initializes the #cipher_state according to BCA +%%------------------------------------------------------------------- +cipher_init(?RC4, IV, Key) -> +    State = crypto:stream_init(rc4, Key), +    #cipher_state{iv = IV, key = Key, state = State}; +cipher_init(?AES_GCM, IV, Key) -> +    <<Nonce:64>> = ssl:random_bytes(8), +    #cipher_state{iv = IV, key = Key, nonce = Nonce}; +cipher_init(_BCA, IV, Key) -> +    #cipher_state{iv = IV, key = Key}. + +%%--------------------------------------------------------------------  -spec cipher(cipher_enum(), #cipher_state{}, binary(), iodata(), ssl_record:ssl_version()) ->  		    {binary(), #cipher_state{}}.   %%  %% Description: Encrypts the data and the MAC using chipher described  %% by cipher_enum() and updating the cipher state +%% Used for "MAC then Cipher" suites where first an HMAC of the +%% data is calculated and the data plus the HMAC is ecncrypted.  %%-------------------------------------------------------------------  cipher(?NULL, CipherState, <<>>, Fragment, _Version) ->      GenStreamCipherList = [Fragment, <<>>],      {GenStreamCipherList, CipherState}; -cipher(?RC4, CipherState, Mac, Fragment, _Version) -> -    State0 = case CipherState#cipher_state.state of -                 undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key); -                 S -> S -             end, +cipher(?RC4, CipherState = #cipher_state{state = State0}, Mac, Fragment, _Version) ->      GenStreamCipherList = [Fragment, Mac],      {State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList),      {T, CipherState#cipher_state{state = State1}}; @@ -113,13 +125,40 @@ cipher(?'3DES', CipherState, Mac, Fragment, Version) ->      block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->  			 crypto:block_encrypt(des3_cbc, [K1, K2, K3], IV, T)  		 end, block_size(des_cbc), CipherState, Mac, Fragment, Version); -cipher(?AES, CipherState, Mac, Fragment, Version) -> +cipher(?AES_CBC, CipherState, Mac, Fragment, Version) ->      block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->  			 crypto:block_encrypt(aes_cbc128, Key, IV, T);  		    (Key, IV, T) when byte_size(Key) =:= 32 ->  			 crypto:block_encrypt(aes_cbc256, Key, IV, T)  		 end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version). +%%-------------------------------------------------------------------- +-spec cipher_aead(cipher_enum(), #cipher_state{}, integer(), binary(), iodata(), ssl_record:ssl_version()) -> +		    {binary(), #cipher_state{}}. +%% +%% Description: Encrypts the data and protects associated data (AAD) using chipher +%% described by cipher_enum() and updating the cipher state +%% Use for suites that use authenticated encryption with associated data (AEAD) +%%------------------------------------------------------------------- +cipher_aead(?AES_GCM, CipherState, SeqNo, AAD, Fragment, Version) -> +    aead_cipher(aes_gcm, CipherState, SeqNo, AAD, Fragment, Version); +cipher_aead(?CHACHA20_POLY1305, CipherState, SeqNo, AAD, Fragment, Version) -> +    aead_cipher(chacha20_poly1305, CipherState, SeqNo, AAD, Fragment, Version). + +aead_cipher(chacha20_poly1305, #cipher_state{key=Key} = CipherState, SeqNo, AAD0, Fragment, _Version) -> +    CipherLen = erlang:iolist_size(Fragment), +    AAD = <<AAD0/binary, ?UINT16(CipherLen)>>, +    Nonce = <<SeqNo:64/integer>>, +    {Content, CipherTag} = crypto:block_encrypt(chacha20_poly1305, Key, Nonce, {AAD, Fragment}), +    {<<Content/binary, CipherTag/binary>>, CipherState}; +aead_cipher(Type, #cipher_state{key=Key, iv = IV0, nonce = Nonce} = CipherState, _SeqNo, AAD0, Fragment, _Version) -> +    CipherLen = erlang:iolist_size(Fragment), +    AAD = <<AAD0/binary, ?UINT16(CipherLen)>>, +    <<Salt:4/bytes, _/binary>> = IV0, +    IV = <<Salt/binary, Nonce:64/integer>>, +    {Content, CipherTag} = crypto:block_encrypt(Type, Key, IV, {AAD, Fragment}), +    {<<Nonce:64/integer, Content/binary, CipherTag/binary>>, CipherState#cipher_state{nonce = Nonce + 1}}. +  build_cipher_block(BlockSz, Mac, Fragment) ->      TotSz = byte_size(Mac) + erlang:iolist_size(Fragment) + 1,      {PaddingLength, Padding} = get_padding(TotSz, BlockSz), @@ -148,14 +187,12 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,  %%  %% Description: Decrypts the data and the MAC using cipher described  %% by cipher_enum() and updating the cipher state. +%% Used for "MAC then Cipher" suites where first the data is decrypted +%% and the an HMAC of the decrypted data is checked  %%-------------------------------------------------------------------  decipher(?NULL, _HashSz, CipherState, Fragment, _) ->      {Fragment, <<>>, CipherState}; -decipher(?RC4, HashSz, CipherState, Fragment, _) -> -    State0 = case CipherState#cipher_state.state of -                 undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key); -                 S -> S -             end, +decipher(?RC4, HashSz, CipherState = #cipher_state{state = State0}, Fragment, _) ->      try crypto:stream_decrypt(State0, Fragment) of  	{State, Text} ->  	    GSC = generic_stream_cipher_from_bin(Text, HashSz), @@ -179,13 +216,26 @@ decipher(?'3DES', HashSz, CipherState, Fragment, Version) ->      block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->  			   crypto:block_decrypt(des3_cbc, [K1, K2, K3], IV, T)  		   end, CipherState, HashSz, Fragment, Version); -decipher(?AES, HashSz, CipherState, Fragment, Version) -> +decipher(?AES_CBC, HashSz, CipherState, Fragment, Version) ->      block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->  			   crypto:block_decrypt(aes_cbc128, Key, IV, T);  		      (Key, IV, T) when byte_size(Key) =:= 32 ->  			   crypto:block_decrypt(aes_cbc256, Key, IV, T)  		   end, CipherState, HashSz, Fragment, Version). +%%-------------------------------------------------------------------- +-spec decipher_aead(cipher_enum(),  #cipher_state{}, integer(), binary(), binary(), ssl_record:ssl_version()) -> +			   {binary(), binary(), #cipher_state{}} | #alert{}. +%% +%% Description: Decrypts the data and checks the associated data (AAD) MAC using +%% cipher described by cipher_enum() and updating the cipher state. +%% Use for suites that use authenticated encryption with associated data (AEAD) +%%------------------------------------------------------------------- +decipher_aead(?AES_GCM, CipherState, SeqNo, AAD, Fragment, Version) -> +    aead_decipher(aes_gcm, CipherState, SeqNo, AAD, Fragment, Version); +decipher_aead(?CHACHA20_POLY1305, CipherState, SeqNo, AAD, Fragment, Version) -> +    aead_decipher(chacha20_poly1305, CipherState, SeqNo, AAD, Fragment, Version). +  block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,   	       HashSz, Fragment, Version) ->      try  @@ -215,6 +265,35 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,  	    %% bad_record_mac alert to hide the specific type of the error."  	    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)      end. + +aead_ciphertext_to_state(chacha20_poly1305, SeqNo, _IV, AAD0, Fragment, _Version) -> +    CipherLen = size(Fragment) - 16, +    <<CipherText:CipherLen/bytes, CipherTag:16/bytes>> = Fragment, +    AAD = <<AAD0/binary, ?UINT16(CipherLen)>>, +    Nonce = <<SeqNo:64/integer>>, +    {Nonce, AAD, CipherText, CipherTag}; +aead_ciphertext_to_state(_, _SeqNo, <<Salt:4/bytes, _/binary>>, AAD0, Fragment, _Version) -> +    CipherLen = size(Fragment) - 24, +    <<ExplicitNonce:8/bytes, CipherText:CipherLen/bytes,  CipherTag:16/bytes>> = Fragment, +    AAD = <<AAD0/binary, ?UINT16(CipherLen)>>, +    Nonce = <<Salt/binary, ExplicitNonce/binary>>, +    {Nonce, AAD, CipherText, CipherTag}. + +aead_decipher(Type, #cipher_state{key = Key, iv = IV} = CipherState, +	      SeqNo, AAD0, Fragment, Version) -> +    try +	{Nonce, AAD, CipherText, CipherTag} = aead_ciphertext_to_state(Type, SeqNo, IV, AAD0, Fragment, Version), +	case crypto:block_decrypt(Type, Key, Nonce, {AAD, CipherText, CipherTag}) of +	    Content when is_binary(Content) -> +		{Content, CipherState}; +	    _ -> +		?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) +	end +    catch +	_:_ -> +	    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) +    end. +  %%--------------------------------------------------------------------  -spec suites(ssl_record:ssl_version()) -> [cipher_suite()].  %% @@ -227,16 +306,26 @@ suites({3, N}) ->  all_suites(Version) ->      suites(Version) -	++ ssl_cipher:anonymous_suites() +	++ ssl_cipher:anonymous_suites(Version)  	++ ssl_cipher:psk_suites(Version)  	++ ssl_cipher:srp_suites().  %%-------------------------------------------------------------------- --spec anonymous_suites() -> [cipher_suite()]. +-spec anonymous_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].  %%  %% Description: Returns a list of the anonymous cipher suites, only supported  %% if explicitly set by user. Intended only for testing.  %%-------------------------------------------------------------------- -anonymous_suites() -> + +anonymous_suites({3, N}) -> +    anonymous_suites(N); + +anonymous_suites(N) +  when N >= 3 -> +    [?TLS_DH_anon_WITH_AES_128_GCM_SHA256, +     ?TLS_DH_anon_WITH_AES_256_GCM_SHA384 +    ] ++ anonymous_suites(0); + +anonymous_suites(_) ->      [?TLS_DH_anon_WITH_RC4_128_MD5,       ?TLS_DH_anon_WITH_DES_CBC_SHA,       ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, @@ -260,13 +349,20 @@ psk_suites({3, N}) ->  psk_suites(N)    when N >= 3 -> -    psk_suites(0) ++ -	[?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, -	 ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, -	 ?TLS_PSK_WITH_AES_256_CBC_SHA384, -	 ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, -	 ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, -	 ?TLS_PSK_WITH_AES_128_CBC_SHA256]; +    [ +     ?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, +     ?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, +     ?TLS_PSK_WITH_AES_256_GCM_SHA384, +     ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, +     ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, +     ?TLS_PSK_WITH_AES_256_CBC_SHA384, +     ?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, +     ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, +     ?TLS_PSK_WITH_AES_128_GCM_SHA256, +     ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, +     ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, +     ?TLS_PSK_WITH_AES_128_CBC_SHA256 +    ] ++ psk_suites(0);  psk_suites(_) ->  	[?TLS_DHE_PSK_WITH_AES_256_CBC_SHA, @@ -418,6 +514,19 @@ suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) ->  %%% TLS 1.2 PSK Cipher Suites RFC 5487 +suite_definition(?TLS_PSK_WITH_AES_128_GCM_SHA256) -> +    {psk, aes_128_gcm, null, sha256}; +suite_definition(?TLS_PSK_WITH_AES_256_GCM_SHA384) -> +    {psk, aes_256_gcm, null, sha384}; +suite_definition(?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256) -> +    {dhe_psk, aes_128_gcm, null, sha256}; +suite_definition(?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384) -> +    {dhe_psk, aes_256_gcm, null, sha384}; +suite_definition(?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256) -> +    {rsa_psk, aes_128_gcm, null, sha256}; +suite_definition(?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384) -> +    {rsa_psk, aes_256_gcm, null, sha384}; +  suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA256) ->      {psk, aes_128_cbc, sha256, default_prf};  suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA384) -> @@ -537,7 +646,59 @@ suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->  suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->      {ecdh_rsa, aes_128_cbc, sha256, sha256};  suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) -> -    {ecdh_rsa, aes_256_cbc, sha384, sha384}. +    {ecdh_rsa, aes_256_cbc, sha384, sha384}; + +%% RFC 5288 AES-GCM Cipher Suites +suite_definition(?TLS_RSA_WITH_AES_128_GCM_SHA256) -> +    {rsa, aes_128_gcm, null, sha256}; +suite_definition(?TLS_RSA_WITH_AES_256_GCM_SHA384) -> +    {rsa, aes_256_gcm, null, sha384}; +suite_definition(?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) -> +    {dhe_rsa, aes_128_gcm, null, sha256}; +suite_definition(?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384) -> +    {dhe_rsa, aes_256_gcm, null, sha384}; +suite_definition(?TLS_DH_RSA_WITH_AES_128_GCM_SHA256) -> +    {dh_rsa, aes_128_gcm, null, sha256}; +suite_definition(?TLS_DH_RSA_WITH_AES_256_GCM_SHA384) -> +    {dh_rsa, aes_256_gcm, null, sha384}; +suite_definition(?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256) -> +    {dhe_dss, aes_128_gcm, null, sha256}; +suite_definition(?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384) -> +    {dhe_dss, aes_256_gcm, null, sha384}; +suite_definition(?TLS_DH_DSS_WITH_AES_128_GCM_SHA256) -> +    {dh_dss, aes_128_gcm, null, sha256}; +suite_definition(?TLS_DH_DSS_WITH_AES_256_GCM_SHA384) -> +    {dh_dss, aes_256_gcm, null, sha384}; +suite_definition(?TLS_DH_anon_WITH_AES_128_GCM_SHA256) -> +    {dh_anon, aes_128_gcm, null, sha256}; +suite_definition(?TLS_DH_anon_WITH_AES_256_GCM_SHA384) -> +    {dh_anon, aes_256_gcm, null, sha384}; + +%% RFC 5289 ECC AES-GCM Cipher Suites +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) -> +    {ecdhe_ecdsa, aes_128_gcm, null, sha256}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) -> +    {ecdhe_ecdsa, aes_256_gcm, null, sha384}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) -> +    {ecdh_ecdsa, aes_128_gcm, null, sha256}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384) -> +    {ecdh_ecdsa, aes_256_gcm, null, sha384}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) -> +    {ecdhe_rsa, aes_128_gcm, null, sha256}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) -> +    {ecdhe_rsa, aes_256_gcm, null, sha384}; +suite_definition(?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256) -> +    {ecdh_rsa, aes_128_gcm, null, sha256}; +suite_definition(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) -> +    {ecdh_rsa, aes_256_gcm, null, sha384}; + +%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites +suite_definition(?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) -> +    {ecdhe_rsa, chacha20_poly1305, null, sha256}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256) -> +    {ecdhe_ecdsa, chacha20_poly1305, null, sha256}; +suite_definition(?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256) -> +    {dhe_rsa, chacha20_poly1305, null, sha256}.  %%--------------------------------------------------------------------  -spec suite(erl_cipher_suite()) -> cipher_suite(). @@ -641,6 +802,19 @@ suite({rsa_psk, aes_256_cbc,sha}) ->  %%% TLS 1.2 PSK Cipher Suites RFC 5487 +suite({psk, aes_128_gcm, null}) -> +    ?TLS_PSK_WITH_AES_128_GCM_SHA256; +suite({psk, aes_256_gcm, null}) -> +    ?TLS_PSK_WITH_AES_256_GCM_SHA384; +suite({dhe_psk, aes_128_gcm, null}) -> +    ?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256; +suite({dhe_psk, aes_256_gcm, null}) -> +    ?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384; +suite({rsa_psk, aes_128_gcm, null}) -> +    ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256; +suite({rsa_psk, aes_256_gcm, null}) -> +    ?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384; +  suite({psk, aes_128_cbc, sha256}) ->      ?TLS_PSK_WITH_AES_128_CBC_SHA256;  suite({psk, aes_256_cbc, sha384}) -> @@ -760,7 +934,60 @@ suite({ecdhe_rsa, aes_256_cbc, sha384}) ->  suite({ecdh_rsa, aes_128_cbc, sha256}) ->      ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;  suite({ecdh_rsa, aes_256_cbc, sha384}) -> -    ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384. +    ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384; + +%% RFC 5288 AES-GCM Cipher Suites +suite({rsa, aes_128_gcm, null}) -> +    ?TLS_RSA_WITH_AES_128_GCM_SHA256; +suite({rsa, aes_256_gcm, null}) -> +    ?TLS_RSA_WITH_AES_256_GCM_SHA384; +suite({dhe_rsa, aes_128_gcm, null}) -> +    ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; +suite({dhe_rsa, aes_256_gcm, null}) -> +    ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384; +suite({dh_rsa, aes_128_gcm, null}) -> +    ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256; +suite({dh_rsa, aes_256_gcm, null}) -> +    ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384; +suite({dhe_dss, aes_128_gcm, null}) -> +    ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256; +suite({dhe_dss, aes_256_gcm, null}) -> +    ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384; +suite({dh_dss, aes_128_gcm, null}) -> +    ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256; +suite({dh_dss, aes_256_gcm, null}) -> +    ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384; +suite({dh_anon, aes_128_gcm, null}) -> +    ?TLS_DH_anon_WITH_AES_128_GCM_SHA256; +suite({dh_anon, aes_256_gcm, null}) -> +    ?TLS_DH_anon_WITH_AES_256_GCM_SHA384; + +%% RFC 5289 ECC AES-GCM Cipher Suites +suite({ecdhe_ecdsa, aes_128_gcm, null}) -> +    ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; +suite({ecdhe_ecdsa, aes_256_gcm, null}) -> +    ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; +suite({ecdh_ecdsa, aes_128_gcm, null}) -> +    ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256; +suite({ecdh_ecdsa, aes_256_gcm, null}) -> +    ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384; +suite({ecdhe_rsa, aes_128_gcm, null}) -> +    ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; +suite({ecdhe_rsa, aes_256_gcm, null}) -> +    ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; +suite({ecdh_rsa, aes_128_gcm, null}) -> +    ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256; +suite({ecdh_rsa, aes_256_gcm, null}) -> +    ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384; + + +%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites +suite({ecdhe_rsa, chacha20_poly1305, null}) -> +    ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; +suite({ecdhe_ecdsa, chacha20_poly1305, null}) -> +    ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; +suite({dhe_rsa, chacha20_poly1305, null}) -> +    ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256.  %%--------------------------------------------------------------------  -spec openssl_suite(openssl_cipher_suite()) -> cipher_suite(). @@ -875,7 +1102,47 @@ openssl_suite("ECDHE-RSA-AES256-SHA384") ->  openssl_suite("ECDH-RSA-AES128-SHA256") ->      ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;  openssl_suite("ECDH-RSA-AES256-SHA384") -> -    ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384. +    ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384; + +%% RFC 5288 AES-GCM Cipher Suites +openssl_suite("AES128-GCM-SHA256") -> +    ?TLS_RSA_WITH_AES_128_GCM_SHA256; +openssl_suite("AES256-GCM-SHA384") -> +    ?TLS_RSA_WITH_AES_256_GCM_SHA384; +openssl_suite("DHE-RSA-AES128-GCM-SHA256") -> +    ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; +openssl_suite("DHE-RSA-AES256-GCM-SHA384") -> +    ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384; +openssl_suite("DH-RSA-AES128-GCM-SHA256") -> +    ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256; +openssl_suite("DH-RSA-AES256-GCM-SHA384") -> +    ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384; +openssl_suite("DHE-DSS-AES128-GCM-SHA256") -> +    ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256; +openssl_suite("DHE-DSS-AES256-GCM-SHA384") -> +    ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384; +openssl_suite("DH-DSS-AES128-GCM-SHA256") -> +    ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256; +openssl_suite("DH-DSS-AES256-GCM-SHA384") -> +    ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384; + +%% RFC 5289 ECC AES-GCM Cipher Suites +openssl_suite("ECDHE-ECDSA-AES128-GCM-SHA256") -> +    ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; +openssl_suite("ECDHE-ECDSA-AES256-GCM-SHA384") -> +    ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; +openssl_suite("ECDH-ECDSA-AES128-GCM-SHA256") -> +    ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256; +openssl_suite("ECDH-ECDSA-AES256-GCM-SHA384") -> +    ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384; +openssl_suite("ECDHE-RSA-AES128-GCM-SHA256") -> +    ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; +openssl_suite("ECDHE-RSA-AES256-GCM-SHA384") -> +    ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; +openssl_suite("ECDH-RSA-AES128-GCM-SHA256") -> +    ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256; +openssl_suite("ECDH-RSA-AES256-GCM-SHA384") -> +    ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384.  %%--------------------------------------------------------------------  -spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite(). @@ -1012,6 +1279,46 @@ openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->  openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->      "ECDH-RSA-AES256-SHA384"; +%% RFC 5288 AES-GCM Cipher Suites +openssl_suite_name(?TLS_RSA_WITH_AES_128_GCM_SHA256) -> +    "AES128-GCM-SHA256"; +openssl_suite_name(?TLS_RSA_WITH_AES_256_GCM_SHA384) -> +    "AES256-GCM-SHA384"; +openssl_suite_name(?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) -> +    "DHE-RSA-AES128-GCM-SHA256"; +openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384) -> +    "DHE-RSA-AES256-GCM-SHA384"; +openssl_suite_name(?TLS_DH_RSA_WITH_AES_128_GCM_SHA256) -> +    "DH-RSA-AES128-GCM-SHA256"; +openssl_suite_name(?TLS_DH_RSA_WITH_AES_256_GCM_SHA384) -> +    "DH-RSA-AES256-GCM-SHA384"; +openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256) -> +    "DHE-DSS-AES128-GCM-SHA256"; +openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384) -> +    "DHE-DSS-AES256-GCM-SHA384"; +openssl_suite_name(?TLS_DH_DSS_WITH_AES_128_GCM_SHA256) -> +    "DH-DSS-AES128-GCM-SHA256"; +openssl_suite_name(?TLS_DH_DSS_WITH_AES_256_GCM_SHA384) -> +    "DH-DSS-AES256-GCM-SHA384"; + +%% RFC 5289 ECC AES-GCM Cipher Suites +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) -> +    "ECDHE-ECDSA-AES128-GCM-SHA256"; +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) -> +    "ECDHE-ECDSA-AES256-GCM-SHA384"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) -> +    "ECDH-ECDSA-AES128-GCM-SHA256"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384) -> +    "ECDH-ECDSA-AES256-GCM-SHA384"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) -> +    "ECDHE-RSA-AES128-GCM-SHA256"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) -> +    "ECDHE-RSA-AES256-GCM-SHA384"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256) -> +    "ECDH-RSA-AES128-GCM-SHA256"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) -> +    "ECDH-RSA-AES256-GCM-SHA384"; +  %% No oppenssl name  openssl_suite_name(Cipher) ->      suite_definition(Cipher). @@ -1095,6 +1402,13 @@ is_acceptable_keyexchange(KeyExchange, Algos)  is_acceptable_keyexchange(_, _) ->      true. +is_acceptable_cipher(Cipher, Algos) +  when Cipher == aes_128_gcm; +       Cipher == aes_256_gcm -> +    proplists:get_bool(aes_gcm, Algos); +is_acceptable_cipher(Cipher, Algos) +  when Cipher == chacha20_poly1305 -> +    proplists:get_bool(Cipher, Algos);  is_acceptable_cipher(_, _) ->      true. @@ -1122,7 +1436,12 @@ bulk_cipher_algorithm('3des_ede_cbc') ->      ?'3DES';  bulk_cipher_algorithm(Cipher) when Cipher == aes_128_cbc;  				   Cipher == aes_256_cbc -> -    ?AES. +    ?AES_CBC; +bulk_cipher_algorithm(Cipher) when Cipher == aes_128_gcm; +				   Cipher == aes_256_gcm -> +    ?AES_GCM; +bulk_cipher_algorithm(chacha20_poly1305) -> +    ?CHACHA20_POLY1305.  type(Cipher) when Cipher == null;  		  Cipher == rc4_128 -> @@ -1132,7 +1451,11 @@ type(Cipher) when Cipher == des_cbc;  		  Cipher == '3des_ede_cbc';  		  Cipher == aes_128_cbc;  		  Cipher == aes_256_cbc -> -    ?BLOCK. +    ?BLOCK; +type(Cipher) when Cipher == aes_128_gcm; +		  Cipher == aes_256_gcm; +		  Cipher == chacha20_poly1305 -> +    ?AEAD.  key_material(null) ->      0; @@ -1145,6 +1468,12 @@ key_material('3des_ede_cbc') ->  key_material(aes_128_cbc) ->      16;  key_material(aes_256_cbc) -> +    32; +key_material(aes_128_gcm) -> +    16; +key_material(aes_256_gcm) -> +    32; +key_material(chacha20_poly1305) ->      32.  expanded_key_material(null) -> @@ -1156,7 +1485,10 @@ expanded_key_material(Cipher) when Cipher == des_cbc ->  expanded_key_material('3des_ede_cbc') ->      24;  expanded_key_material(Cipher) when Cipher == aes_128_cbc; - 				   Cipher == aes_256_cbc -> +				   Cipher == aes_256_cbc; +				   Cipher == aes_128_gcm; +				   Cipher == aes_256_gcm; +				   Cipher == chacha20_poly1305 ->      unknown.   @@ -1165,16 +1497,25 @@ effective_key_bits(null) ->  effective_key_bits(des_cbc) ->      56;  effective_key_bits(Cipher) when Cipher == rc4_128; -				Cipher == aes_128_cbc -> +				Cipher == aes_128_cbc; +				Cipher == aes_128_gcm ->      128;  effective_key_bits('3des_ede_cbc') ->      168; -effective_key_bits(aes_256_cbc) -> +effective_key_bits(Cipher) when Cipher == aes_256_cbc; +				Cipher == aes_256_gcm; +				Cipher == chacha20_poly1305 ->      256.  iv_size(Cipher) when Cipher == null; -		     Cipher == rc4_128 -> +		     Cipher == rc4_128; +		     Cipher == chacha20_poly1305->      0; + +iv_size(Cipher) when Cipher == aes_128_gcm; +		     Cipher == aes_256_gcm -> +    4; +  iv_size(Cipher) ->      block_size(Cipher). @@ -1183,7 +1524,10 @@ block_size(Cipher) when Cipher == des_cbc;      8;  block_size(Cipher) when Cipher == aes_128_cbc; -			Cipher == aes_256_cbc -> +			Cipher == aes_256_cbc; +			Cipher == aes_128_gcm; +			Cipher == aes_256_gcm; +			Cipher == chacha20_poly1305 ->      16.  prf_algorithm(default_prf, {3, N}) when N >= 3 -> @@ -1337,10 +1681,15 @@ dhe_rsa_suites() ->       ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,       ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,       ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, -     ?TLS_DHE_RSA_WITH_DES_CBC_SHA]. +     ?TLS_DHE_RSA_WITH_DES_CBC_SHA, +     ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, +     ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, +     ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256].  psk_rsa_suites() -> -    [?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, +    [?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, +     ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, +     ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,       ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,       ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,       ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA, @@ -1360,7 +1709,9 @@ rsa_suites() ->       ?TLS_RSA_WITH_AES_128_CBC_SHA,       ?TLS_RSA_WITH_RC4_128_SHA,       ?TLS_RSA_WITH_RC4_128_MD5, -     ?TLS_RSA_WITH_DES_CBC_SHA]. +     ?TLS_RSA_WITH_DES_CBC_SHA, +     ?TLS_RSA_WITH_AES_128_GCM_SHA256, +     ?TLS_RSA_WITH_AES_256_GCM_SHA384].  ecdh_rsa_suites() ->      [?TLS_ECDH_RSA_WITH_NULL_SHA, @@ -1369,7 +1720,9 @@ ecdh_rsa_suites() ->       ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,       ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,       ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, -     ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384]. +     ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, +     ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, +     ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384].  ecdhe_rsa_suites() ->      [?TLS_ECDHE_RSA_WITH_NULL_SHA, @@ -1378,7 +1731,10 @@ ecdhe_rsa_suites() ->       ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,       ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,       ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, -     ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384]. +     ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, +     ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, +     ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, +     ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256].  dsa_signed_suites() ->      dhe_dss_suites() ++ srp_dss_suites(). @@ -1389,7 +1745,9 @@ dhe_dss_suites()  ->       ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,       ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,       ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, -     ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA]. +     ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, +     ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, +     ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384].  srp_dss_suites() ->      [?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, @@ -1413,7 +1771,9 @@ ecdh_ecdsa_suites() ->       ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,       ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,       ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, -     ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384]. +     ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, +     ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, +     ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384].  ecdhe_ecdsa_suites() ->      [?TLS_ECDHE_ECDSA_WITH_NULL_SHA, @@ -1422,7 +1782,10 @@ ecdhe_ecdsa_suites() ->       ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,       ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,       ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, -     ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384]. +     ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, +     ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, +     ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, +     ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256].  filter_keyuse(OtpCert, Ciphers, Suites, SignSuites) ->      TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,  diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 3ce9c19aa9..448c2405aa 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -46,7 +46,8 @@  -record(cipher_state, {  	  iv,  	  key, -	  state +	  state, +	  nonce  	 }).  %%% TLS_NULL_WITH_NULL_NULL is specified and is the initial state of a @@ -395,6 +396,24 @@  %%% TLS 1.2 PSK Cipher Suites RFC 5487 +%%      TLS_PSK_WITH_AES_128_GCM_SHA256       = {0x00,0xA8}; +-define(TLS_PSK_WITH_AES_128_GCM_SHA256, <<?BYTE(16#00), ?BYTE(16#A8)>>). + +%%      TLS_PSK_WITH_AES_256_GCM_SHA384       = {0x00,0xA9}; +-define(TLS_PSK_WITH_AES_256_GCM_SHA384, <<?BYTE(16#00), ?BYTE(16#A9)>>). + +%%      TLS_DHE_PSK_WITH_AES_128_GCM_SHA256   = {0x00,0xAA}; +-define(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, <<?BYTE(16#00), ?BYTE(16#AA)>>). + +%%      TLS_DHE_PSK_WITH_AES_256_GCM_SHA384   = {0x00,0xAB}; +-define(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, <<?BYTE(16#00), ?BYTE(16#AB)>>). + +%%      TLS_RSA_PSK_WITH_AES_128_GCM_SHA256   = {0x00,0xAC}; +-define(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, <<?BYTE(16#00), ?BYTE(16#AC)>>). + +%%      TLS_RSA_PSK_WITH_AES_256_GCM_SHA384   = {0x00,0xAD}; +-define(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, <<?BYTE(16#00), ?BYTE(16#AD)>>). +  %%      TLS_PSK_WITH_AES_128_CBC_SHA256       = {0x00,0xAE};  -define(TLS_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#AE)>>). @@ -460,4 +479,79 @@  %%      TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA  = { 0xC0,0x22 };  -define(TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#22)>>). +%%% AES-GCM Cipher Suites RFC 5288 + +%%      TLS_RSA_WITH_AES_128_GCM_SHA256     = {0x00,0x9C} +-define(TLS_RSA_WITH_AES_128_GCM_SHA256, <<?BYTE(16#00), ?BYTE(16#9C)>>). + +%%      TLS_RSA_WITH_AES_256_GCM_SHA384     = {0x00,0x9D} +-define(TLS_RSA_WITH_AES_256_GCM_SHA384, <<?BYTE(16#00), ?BYTE(16#9D)>>). + +%%      TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = {0x00,0x9E} +-define(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, <<?BYTE(16#00), ?BYTE(16#9E)>>). + +%%      TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = {0x00,0x9F} +-define(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, <<?BYTE(16#00), ?BYTE(16#9F)>>). + +%%      TLS_DH_RSA_WITH_AES_128_GCM_SHA256  = {0x00,0xA0} +-define(TLS_DH_RSA_WITH_AES_128_GCM_SHA256, <<?BYTE(16#00), ?BYTE(16#A0)>>). + +%%      TLS_DH_RSA_WITH_AES_256_GCM_SHA384  = {0x00,0xA1} +-define(TLS_DH_RSA_WITH_AES_256_GCM_SHA384, <<?BYTE(16#00), ?BYTE(16#A1)>>). + +%%      TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = {0x00,0xA2} +-define(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, <<?BYTE(16#00), ?BYTE(16#A2)>>). + +%%      TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = {0x00,0xA3} +-define(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, <<?BYTE(16#00), ?BYTE(16#A3)>>). + +%%      TLS_DH_DSS_WITH_AES_128_GCM_SHA256  = {0x00,0xA4} +-define(TLS_DH_DSS_WITH_AES_128_GCM_SHA256, <<?BYTE(16#00), ?BYTE(16#A4)>>). + +%%      TLS_DH_DSS_WITH_AES_256_GCM_SHA384  = {0x00,0xA5} +-define(TLS_DH_DSS_WITH_AES_256_GCM_SHA384, <<?BYTE(16#00), ?BYTE(16#A5)>>). + +%%      TLS_DH_anon_WITH_AES_128_GCM_SHA256 = {0x00,0xA6} +-define(TLS_DH_anon_WITH_AES_128_GCM_SHA256, <<?BYTE(16#00), ?BYTE(16#A6)>>). + +%%      TLS_DH_anon_WITH_AES_256_GCM_SHA384 = {0x00,0xA7} +-define(TLS_DH_anon_WITH_AES_256_GCM_SHA384, <<?BYTE(16#00), ?BYTE(16#A7)>>). + +%%% ECC AES-GCM Cipher Suites RFC 5289 + +%%      TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256  = {0xC0,0x2B}; +-define(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, <<?BYTE(16#C0), ?BYTE(16#2B)>>). + +%%      TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384  = {0xC0,0x2C}; +-define(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, <<?BYTE(16#C0), ?BYTE(16#2C)>>). + +%%      TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256   = {0xC0,0x2D}; +-define(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, <<?BYTE(16#C0), ?BYTE(16#2D)>>). + +%%      TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384   = {0xC0,0x2E}; +-define(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, <<?BYTE(16#C0), ?BYTE(16#2E)>>). + +%%      TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256    = {0xC0,0x2F}; +-define(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, <<?BYTE(16#C0), ?BYTE(16#2F)>>). + +%%      TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384    = {0xC0,0x30}; +-define(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, <<?BYTE(16#C0), ?BYTE(16#30)>>). + +%%      TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256     = {0xC0,0x31}; +-define(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, <<?BYTE(16#C0), ?BYTE(16#31)>>). + +%%      TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384     = {0xC0,0x32}; +-define(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, <<?BYTE(16#C0), ?BYTE(16#32)>>). + +%%% Chacha20/Poly1305 Suites draft-agl-tls-chacha20poly1305-04 + +%%      TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256   = {0xcc, 0x13} +-define(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#13)>>). + +%%      TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = {0xcc, 0x14} +-define(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#14)>>). + +%%      TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256     = {0xcc, 0x15} +-define(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#15)>>). +  -endif. % -ifdef(ssl_cipher). diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 88ccb94e0b..07535e79b4 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1435,6 +1435,7 @@ calc_finished({3, N}, Role, PrfAlgo, MasterSecret, Handshake) ->  master_secret(_RecordCB, Version, MasterSecret,  	      #security_parameters{ +		 bulk_cipher_algorithm = BCA,  		 client_random = ClientRandom,  		 server_random = ServerRandom,  		 hash_size = HashSize, @@ -1453,8 +1454,8 @@ master_secret(_RecordCB, Version, MasterSecret,  	ssl_record:set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret,  				  Role, ConnStates1), -    ClientCipherState = #cipher_state{iv = ClientIV, key = ClientWriteKey}, -    ServerCipherState = #cipher_state{iv = ServerIV, key = ServerWriteKey}, +    ClientCipherState = ssl_cipher:cipher_init(BCA, ClientIV, ClientWriteKey), +    ServerCipherState = ssl_cipher:cipher_init(BCA, ServerIV, ServerWriteKey),      {MasterSecret,       ssl_record:set_pending_cipher_state(ConnStates2, ClientCipherState,  					 ServerCipherState, Role)}. diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index d6e5064c39..5553fc9220 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2007-2013. All Rights Reserved. +%% Copyright Ericsson AB 2007-2014. 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 @@ -44,7 +44,8 @@  -include_lib("kernel/include/file.hrl").  -record(state, { -	  session_cache, +	  session_cache_client, +	  session_cache_server,  	  session_cache_cb,  	  session_lifetime,  	  certificate_db, @@ -209,12 +210,16 @@ init([Name, Opts]) ->      SessionLifeTime =    	proplists:get_value(session_lifetime, Opts, ?'24H_in_sec'),      CertDb = ssl_pkix_db:create(), -    SessionCache = CacheCb:init(proplists:get_value(session_cb_init_args, Opts, [])), +    ClientSessionCache = CacheCb:init([{role, client} |  +				       proplists:get_value(session_cb_init_args, Opts, [])]), +    ServerSessionCache = CacheCb:init([{role, server} |  +				       proplists:get_value(session_cb_init_args, Opts, [])]),      Timer = erlang:send_after(SessionLifeTime * 1000 + 5000,   			      self(), validate_sessions),      erlang:send_after(?CLEAR_PEM_CACHE, self(), clear_pem_cache),      {ok, #state{certificate_db = CertDb, -		session_cache = SessionCache, +		session_cache_client = ClientSessionCache, +		session_cache_server = ServerSessionCache,  		session_cache_cb = CacheCb,  		session_lifetime = SessionLifeTime,  		session_validation_timer = Timer}}. @@ -230,15 +235,32 @@ init([Name, Opts]) ->  %%  %% Description: Handling call messages  %%-------------------------------------------------------------------- -handle_call({{connection_init, <<>>, _Role}, _Pid}, _From, +handle_call({{connection_init, <<>>, client}, _Pid}, _From,  	    #state{certificate_db = [CertDb, FileRefDb, PemChace], -		   session_cache = Cache} = State) -> +		   session_cache_client = Cache} = State) -> +    Result = {ok, make_ref(),CertDb, FileRefDb, PemChace, Cache}, +    {reply, Result, State}; +handle_call({{connection_init, <<>>, server}, _Pid}, _From, +	    #state{certificate_db = [CertDb, FileRefDb, PemChace], +		   session_cache_server = Cache} = State) ->      Result = {ok, make_ref(),CertDb, FileRefDb, PemChace, Cache},      {reply, Result, State}; -handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From, +handle_call({{connection_init, Trustedcerts, client}, Pid}, _From, +	    #state{certificate_db = [CertDb, FileRefDb, PemChace] = Db, +		   session_cache_client = Cache} = State) -> +    Result =  +	try +	    {ok, Ref} = ssl_pkix_db:add_trusted_certs(Pid, Trustedcerts, Db), +	    {ok, Ref, CertDb, FileRefDb, PemChace, Cache} +	catch +	    _:Reason -> +		{error, Reason} +	end, +    {reply, Result, State}; +handle_call({{connection_init, Trustedcerts, server}, Pid}, _From,  	    #state{certificate_db = [CertDb, FileRefDb, PemChace] = Db, -		   session_cache = Cache} = State) -> +		   session_cache_server = Cache} = State) ->      Result =   	try  	    {ok, Ref} = ssl_pkix_db:add_trusted_certs(Pid, Trustedcerts, Db), @@ -249,9 +271,10 @@ handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From,  	end,      {reply, Result, State}; +  handle_call({{new_session_id,Port}, _},  	    _, #state{session_cache_cb = CacheCb, -		      session_cache = Cache} = State) -> +		      session_cache_server = Cache} = State) ->      Id = new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb),      {reply, Id, State}; @@ -278,16 +301,22 @@ handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_  %% Description: Handling cast messages  %%--------------------------------------------------------------------  handle_cast({register_session, Host, Port, Session},  -	    #state{session_cache = Cache, +	    #state{session_cache_client = Cache,  		   session_cache_cb = CacheCb} = State) ->      TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}),      NewSession = Session#session{time_stamp = TimeStamp}, -    CacheCb:update(Cache, {{Host, Port},  -		   NewSession#session.session_id}, NewSession), +     +    case CacheCb:select_session(Cache, {Host, Port}) of +	no_session -> +	    CacheCb:update(Cache, {{Host, Port},  +				   NewSession#session.session_id}, NewSession); +	Sessions -> +	    register_unique_session(Sessions, NewSession, CacheCb, Cache, {Host, Port}) +    end,      {noreply, State};  handle_cast({register_session, Port, Session},   -	    #state{session_cache = Cache, +	    #state{session_cache_server = Cache,  		   session_cache_cb = CacheCb} = State) ->          TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}),      NewSession = Session#session{time_stamp = TimeStamp}, @@ -296,12 +325,12 @@ handle_cast({register_session, Port, Session},  handle_cast({invalidate_session, Host, Port,  	     #session{session_id = ID} = Session}, -	    #state{session_cache = Cache, +	    #state{session_cache_client = Cache,  		   session_cache_cb = CacheCb} = State) ->      invalidate_session(Cache, CacheCb, {{Host, Port}, ID}, Session, State);  handle_cast({invalidate_session, Port, #session{session_id = ID} = Session}, -	    #state{session_cache = Cache, +	    #state{session_cache_server = Cache,  		   session_cache_cb = CacheCb} = State) ->      invalidate_session(Cache, CacheCb, {Port, ID}, Session, State). @@ -314,17 +343,18 @@ handle_cast({invalidate_session, Port, #session{session_id = ID} = Session},  %% Description: Handling all non call/cast messages  %%-------------------------------------------------------------------  handle_info(validate_sessions, #state{session_cache_cb = CacheCb, -				      session_cache = Cache, +				      session_cache_client = ClientCache, +				      session_cache_server = ServerCache,  				      session_lifetime = LifeTime  				     } = State) ->      Timer = erlang:send_after(?SESSION_VALIDATION_INTERVAL,   			      self(), validate_sessions), -    start_session_validator(Cache, CacheCb, LifeTime), +    start_session_validator(ClientCache, CacheCb, LifeTime), +    start_session_validator(ServerCache, CacheCb, LifeTime),      {noreply, State#state{session_validation_timer = Timer}}; -handle_info({delayed_clean_session, Key}, #state{session_cache = Cache, -                   session_cache_cb = CacheCb -                   } = State) -> +handle_info({delayed_clean_session, Key, Cache}, #state{session_cache_cb = CacheCb +						       } = State) ->      CacheCb:delete(Cache, Key),      {noreply, State}; @@ -367,12 +397,14 @@ handle_info(_Info, State) ->  %% The return value is ignored.  %%--------------------------------------------------------------------  terminate(_Reason, #state{certificate_db = Db, -			  session_cache = SessionCache, +			  session_cache_client = ClientSessionCache, +			  session_cache_server = ServerSessionCache,  			  session_cache_cb = CacheCb,  			  session_validation_timer = Timer}) ->      erlang:cancel_timer(Timer),      ssl_pkix_db:remove(Db), -    CacheCb:terminate(SessionCache), +    catch CacheCb:terminate(ClientSessionCache), +    catch CacheCb:terminate(ServerSessionCache),      ok.  %%-------------------------------------------------------------------- @@ -445,7 +477,7 @@ invalidate_session(Cache, CacheCb, Key, Session, #state{last_delay_timer = LastT  	    %% up the session data but new connections should not get to use this session.  	    CacheCb:update(Cache, Key, Session#session{is_resumable = false}),  	    TRef = -		erlang:send_after(delay_time(), self(), {delayed_clean_session, Key}), +		erlang:send_after(delay_time(), self(), {delayed_clean_session, Key, Cache}),  	    {noreply, State#state{last_delay_timer = last_delay_timer(Key, TRef, LastTimer)}}      end. @@ -494,3 +526,34 @@ clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->  	_ ->  	    ok      end. + +%% Do not let dumb clients create a gigantic session table +%% for itself creating big delays at connection time.  +register_unique_session(Sessions, Session, CacheCb, Cache, PartialKey) -> +    case exists_equivalent(Session , Sessions) of +	true -> +	    ok; +	false -> +	    CacheCb:update(Cache, {PartialKey,  +				   Session#session.session_id}, Session) +    end. + +exists_equivalent(_, []) -> +    false; +exists_equivalent(#session{ +		     peer_certificate = PeerCert, +		     own_certificate = OwnCert, +		     compression_method = Compress, +		     cipher_suite = CipherSuite, +		     srp_username = SRP, +		     ecc = ECC} ,  +		  [#session{ +		      peer_certificate = PeerCert, +		      own_certificate = OwnCert, +		      compression_method = Compress, +		      cipher_suite = CipherSuite, +		      srp_username = SRP, +		      ecc = ECC} | _]) -> +    true; +exists_equivalent(Session, [ _ | Rest]) -> +    exists_equivalent(Session, Rest). diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 7337225bc4..63fc57edad 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -48,7 +48,8 @@  -export([compress/3, uncompress/3, compressions/0]).  %% Payload encryption/decryption --export([cipher/4, decipher/3, is_correct_mac/2]). +-export([cipher/4, decipher/3, is_correct_mac/2, +	 cipher_aead/4, decipher_aead/4]).  -export_type([ssl_version/0, ssl_atom_version/0]). @@ -377,6 +378,24 @@ cipher(Version, Fragment,  	ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MacHash, Fragment, Version),      {CipherFragment,  WriteState0#connection_state{cipher_state = CipherS1}}.  %%-------------------------------------------------------------------- +-spec cipher_aead(ssl_version(), iodata(), #connection_state{}, MacHash::binary()) -> +			 {CipherFragment::binary(), #connection_state{}}. +%% +%% Description: Payload encryption +%%-------------------------------------------------------------------- +cipher_aead(Version, Fragment, +       #connection_state{cipher_state = CipherS0, +			 sequence_number = SeqNo, +			 security_parameters= +			     #security_parameters{bulk_cipher_algorithm = +						      BulkCipherAlgo} +			} = WriteState0, AAD) -> + +    {CipherFragment, CipherS1} = +	ssl_cipher:cipher_aead(BulkCipherAlgo, CipherS0, SeqNo, AAD, Fragment, Version), +    {CipherFragment,  WriteState0#connection_state{cipher_state = CipherS1}}. + +%%--------------------------------------------------------------------  -spec decipher(ssl_version(), binary(), #connection_state{}) -> {binary(), binary(), #connection_state{}} | #alert{}.  %%  %% Description: Payload decryption @@ -396,6 +415,25 @@ decipher(Version, CipherFragment,  	    Alert      end.  %%-------------------------------------------------------------------- +-spec decipher_aead(ssl_version(), binary(), #connection_state{}, binary()) -> {binary(), binary(), #connection_state{}} | #alert{}. +%% +%% Description: Payload decryption +%%-------------------------------------------------------------------- +decipher_aead(Version, CipherFragment, +	 #connection_state{sequence_number = SeqNo, +			   security_parameters = +			       #security_parameters{bulk_cipher_algorithm = +							BulkCipherAlgo}, +			   cipher_state = CipherS0 +			  } = ReadState, AAD) -> +    case ssl_cipher:decipher_aead(BulkCipherAlgo, CipherS0, SeqNo, AAD, CipherFragment, Version) of +	{PlainFragment, CipherS1} -> +	    CS1 = ReadState#connection_state{cipher_state = CipherS1}, +	    {PlainFragment, CS1}; +	#alert{} = Alert -> +	    Alert +    end. +%%--------------------------------------------------------------------  %%% Internal functions  %%--------------------------------------------------------------------  empty_connection_state(ConnectionEnd) -> diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl index 6aab35d6da..53b5f2399b 100644 --- a/lib/ssl/src/ssl_record.hrl +++ b/lib/ssl/src/ssl_record.hrl @@ -90,11 +90,14 @@  -define('3DES', 4).  -define(DES40, 5).  -define(IDEA, 6). --define(AES, 7).  +-define(AES_CBC, 7). +-define(AES_GCM, 8). +-define(CHACHA20_POLY1305, 9).  %% CipherType  -define(STREAM, 0).  -define(BLOCK, 1). +-define(AEAD, 2).  %% IsExportable  %-define(TRUE, 0).  %% Already defined by ssl_internal.hrl diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl index 5c6ee3c54c..b011732f2c 100644 --- a/lib/ssl/src/ssl_session_cache.erl +++ b/lib/ssl/src/ssl_session_cache.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. 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 @@ -31,8 +31,8 @@  %%--------------------------------------------------------------------  %% Description: Return table reference. Called by ssl_manager process.   %%-------------------------------------------------------------------- -init(_) -> -    ets:new(cache_name(), [ordered_set, protected]). +init(Options) -> +    ets:new(cache_name(proplists:get_value(role, Options)), [ordered_set, protected]).  %%--------------------------------------------------------------------  %% Description: Handles cache table at termination of ssl manager.  @@ -87,5 +87,5 @@ select_session(Cache, PartialKey) ->  %%--------------------------------------------------------------------  %%% Internal functions  %%-------------------------------------------------------------------- -cache_name() -> -    ssl_otp_session_cache. +cache_name(Name) -> +    list_to_atom(atom_to_list(Name) ++ "_ssl_otp_session_cache"). diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl index f50ea22f39..544d200f70 100644 --- a/lib/ssl/src/tls_record.erl +++ b/lib/ssl/src/tls_record.erl @@ -132,6 +132,23 @@ encode_plain_text(Type, Version, Data,  					    sequence_number = Seq,  					    compression_state=CompS0,  					    security_parameters= +						#security_parameters{ +						   cipher_type = ?AEAD, +						   compression_algorithm=CompAlg} +					   }= WriteState0} = ConnectionStates) -> +    {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0), +    WriteState1 = WriteState0#connection_state{compression_state = CompS1}, +    AAD = calc_aad(Type, Version, WriteState1), +    {CipherFragment, WriteState} = ssl_record:cipher_aead(Version, Comp, WriteState1, AAD), +    CipherText = encode_tls_cipher_text(Type, Version, CipherFragment), +    {CipherText, ConnectionStates#connection_states{current_write = WriteState#connection_state{sequence_number = Seq +1}}}; + +encode_plain_text(Type, Version, Data, +		  #connection_states{current_write = +					 #connection_state{ +					    sequence_number = Seq, +					    compression_state=CompS0, +					    security_parameters=  						#security_parameters{compression_algorithm=CompAlg}  					   }= WriteState0} = ConnectionStates) ->      {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0), @@ -148,18 +165,45 @@ encode_plain_text(Type, Version, Data,  %% Description: Decode cipher text  %%--------------------------------------------------------------------  decode_cipher_text(#ssl_tls{type = Type, version = Version, -			    fragment = CipherFragment} = CipherText, ConnnectionStates0) -> -    ReadState0 = ConnnectionStates0#connection_states.current_read, -    #connection_state{compression_state = CompressionS0, -		      sequence_number = Seq, -		      security_parameters = SecParams} = ReadState0, -    CompressAlg = SecParams#security_parameters.compression_algorithm, +			    fragment = CipherFragment} = CipherText, +		   #connection_states{current_read = +					  #connection_state{ +					     compression_state = CompressionS0, +					     sequence_number = Seq, +					     security_parameters= +						 #security_parameters{ +						    cipher_type = ?AEAD, +						    compression_algorithm=CompAlg} +					    } = ReadState0} = ConnnectionStates0) -> +    AAD = calc_aad(Type, Version, ReadState0), +    case ssl_record:decipher_aead(Version, CipherFragment, ReadState0, AAD) of +	{PlainFragment, ReadState1} -> +	    {Plain, CompressionS1} = ssl_record:uncompress(CompAlg, +							   PlainFragment, CompressionS0), +	    ConnnectionStates = ConnnectionStates0#connection_states{ +				  current_read = ReadState1#connection_state{ +						   sequence_number = Seq + 1, +						   compression_state = CompressionS1}}, +	    {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates}; +	#alert{} = Alert -> +	    Alert +    end; + +decode_cipher_text(#ssl_tls{type = Type, version = Version, +			    fragment = CipherFragment} = CipherText, +		   #connection_states{current_read = +					  #connection_state{ +					     compression_state = CompressionS0, +					     sequence_number = Seq, +					     security_parameters= +						 #security_parameters{compression_algorithm=CompAlg} +					    } = ReadState0} = ConnnectionStates0) ->      case ssl_record:decipher(Version, CipherFragment, ReadState0) of  	{PlainFragment, Mac, ReadState1} ->  	    MacHash = calc_mac_hash(Type, Version, PlainFragment, ReadState1),  	    case ssl_record:is_correct_mac(Mac, MacHash) of  		true -> -		    {Plain, CompressionS1} = ssl_record:uncompress(CompressAlg, +		    {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,  								   PlainFragment, CompressionS0),  		    ConnnectionStates = ConnnectionStates0#connection_states{  					  current_read = ReadState1#connection_state{ @@ -322,3 +366,7 @@ calc_mac_hash(Type, Version,      mac_hash(Version, SecPars#security_parameters.mac_algorithm,  	     MacSecret, SeqNo, Type,  	     Length, PlainFragment). + +calc_aad(Type, {MajVer, MinVer}, +	 #connection_state{sequence_number = SeqNo}) -> +    <<SeqNo:64/integer, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>. diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl index 7a5f9c1b38..c4114278a4 100644 --- a/lib/ssl/src/tls_v1.erl +++ b/lib/ssl/src/tls_v1.erl @@ -221,25 +221,50 @@ suites(Minor) when Minor == 1; Minor == 2 ->      ];  suites(3) ->      [ +     ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, +     ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + +     ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, +     ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,       ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,       ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, +     ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, +     ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,       ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,       ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, +     ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +     ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, +     ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,       ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,       ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, +     ?TLS_RSA_WITH_AES_256_GCM_SHA384,       ?TLS_RSA_WITH_AES_256_CBC_SHA256, +     ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, +     ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,       ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,       ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, +     ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, +     ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,       ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,       ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, +     ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, +     ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,       ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,       ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, +     ?TLS_RSA_WITH_AES_128_GCM_SHA256,       ?TLS_RSA_WITH_AES_128_CBC_SHA256 + +     %% not supported +     %% ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384, +     %% ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384, +     %% ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256, +     %% ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256      ] ++ suites(2). +  %%--------------------------------------------------------------------  %%% Internal functions  %%-------------------------------------------------------------------- | 
