diff options
Diffstat (limited to 'lib/ssl/src/ssl_cipher.erl')
| -rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 1735 |
1 files changed, 1543 insertions, 192 deletions
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 72f02a4362..32fec03b8e 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -1,18 +1,19 @@ -%% +% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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/. +%% http://www.apache.org/licenses/LICENSE-2.0 %% -%% 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. +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% @@ -28,25 +29,60 @@ -include("ssl_internal.hrl"). -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). +-include("ssl_handshake.hrl"). -include("ssl_alert.hrl"). -include_lib("public_key/include/public_key.hrl"). --export([security_parameters/2, suite_definition/1, - decipher/5, cipher/4, - suite/1, suites/1, anonymous_suites/0, - openssl_suite/1, openssl_suite_name/1, filter/2]). +-export([security_parameters/2, security_parameters/3, suite_definition/1, + erl_suite_definition/1, + cipher_init/3, decipher/6, cipher/5, decipher_aead/6, cipher_aead/6, + suite/1, suites/1, all_suites/1, + ec_keyed_suites/0, anonymous_suites/1, psk_suites/1, srp_suites/0, + rc4_suites/1, des_suites/1, openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1, + hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2, is_fallback/1, + random_bytes/1, calc_aad/3, calc_mac_hash/4]). + +-export_type([cipher_suite/0, + erl_cipher_suite/0, openssl_cipher_suite/0, + hash/0, key_algo/0, sign_algo/0]). + +-type cipher() :: null |rc4_128 | des_cbc | '3des_ede_cbc' + | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305. +-type hash() :: null | md5 | sha | sha224 | sha256 | sha384 | sha512. +-type sign_algo() :: rsa | dsa | ecdsa. +-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()} % Pre TLS 1.2 + %% TLS 1.2, internally PRE TLS 1.2 will use default_prf + | {key_algo(), cipher(), hash(), hash() | default_prf}. + + +-type cipher_suite() :: binary(). +-type cipher_enum() :: integer(). +-type openssl_cipher_suite() :: string(). + -compile(inline). %%-------------------------------------------------------------------- --spec security_parameters(cipher_suite(), #security_parameters{}) -> +-spec security_parameters(cipher_suite(), #security_parameters{}) -> + #security_parameters{}. +%% Only security_parameters/2 should call security_parameters/3 with undefined as +%% first argument. +%%-------------------------------------------------------------------- + +security_parameters(?TLS_NULL_WITH_NULL_NULL = CipherSuite, SecParams) -> + security_parameters(undefined, CipherSuite, SecParams). + +%%-------------------------------------------------------------------- +-spec security_parameters(ssl_record:ssl_version() | undefined, cipher_suite(), #security_parameters{}) -> #security_parameters{}. %% %% Description: Returns a security parameters record where the %% cipher values has been updated according to <CipherSuite> %%------------------------------------------------------------------- -security_parameters(CipherSuite, SecParams) -> - { _, Cipher, Hash} = suite_definition(CipherSuite), +security_parameters(Version, CipherSuite, SecParams) -> + { _, Cipher, Hash, PrfHashAlg} = suite_definition(CipherSuite), SecParams#security_parameters{ cipher_suite = CipherSuite, bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher), @@ -55,70 +91,118 @@ security_parameters(CipherSuite, SecParams) -> expanded_key_material_length = expanded_key_material(Cipher), key_material_length = key_material(Cipher), iv_size = iv_size(Cipher), - mac_algorithm = mac_algorithm(Hash), + mac_algorithm = hash_algorithm(Hash), + prf_algorithm = prf_algorithm(PrfHashAlg, Version), hash_size = hash_size(Hash)}. %%-------------------------------------------------------------------- --spec cipher(cipher_enum(), #cipher_state{}, binary(), binary()) -> +-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>> = 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) -> +cipher(?NULL, CipherState, <<>>, Fragment, _Version) -> GenStreamCipherList = [Fragment, <<>>], {GenStreamCipherList, CipherState}; -cipher(?RC4, CipherState, Mac, Fragment) -> - State0 = case CipherState#cipher_state.state of - undefined -> crypto:rc4_set_key(CipherState#cipher_state.key); - S -> S - end, +cipher(?RC4, CipherState = #cipher_state{state = State0}, Mac, Fragment, _Version) -> GenStreamCipherList = [Fragment, Mac], - {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList), + {State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList), {T, CipherState#cipher_state{state = State1}}; -cipher(?DES, CipherState, Mac, Fragment) -> +cipher(?DES, CipherState, Mac, Fragment, Version) -> block_cipher(fun(Key, IV, T) -> - crypto:des_cbc_encrypt(Key, IV, T) - end, block_size(des_cbc), CipherState, Mac, Fragment); -cipher(?'3DES', CipherState, Mac, Fragment) -> + crypto:block_encrypt(des_cbc, Key, IV, T) + end, block_size(des_cbc), CipherState, Mac, Fragment, Version); +cipher(?'3DES', CipherState, Mac, Fragment, Version) -> block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) -> - crypto:des3_cbc_encrypt(K1, K2, K3, IV, T) - end, block_size(des_cbc), CipherState, Mac, Fragment); -cipher(?AES, CipherState, Mac, Fragment) -> + crypto:block_encrypt(des3_cbc, [K1, K2, K3], IV, T) + end, block_size(des_cbc), CipherState, Mac, Fragment, Version); +cipher(?AES_CBC, CipherState, Mac, Fragment, Version) -> block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 -> - crypto:aes_cbc_128_encrypt(Key, IV, T); + crypto:block_encrypt(aes_cbc128, Key, IV, T); (Key, IV, T) when byte_size(Key) =:= 32 -> - crypto:aes_cbc_256_encrypt(Key, IV, T) - end, block_size(aes_128_cbc), CipherState, Mac, Fragment). -%% cipher(?IDEA, CipherState, Mac, Fragment) -> -%% block_cipher(fun(Key, IV, T) -> -%% crypto:idea_cbc_encrypt(Key, IV, T) -%% end, block_size(idea_cbc), CipherState, Mac, Fragment); - -block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, - Mac, Fragment) -> + 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), - L = [Fragment, Mac, PaddingLength, Padding], + [Fragment, Mac, PaddingLength, Padding]. + +block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, + Mac, Fragment, {3, N}) + when N == 0; N == 1 -> + L = build_cipher_block(BlockSz, Mac, Fragment), T = Fun(Key, IV, L), NextIV = next_iv(T, IV), + {T, CS0#cipher_state{iv=NextIV}}; + +block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, + Mac, Fragment, {3, N}) + when N == 2; N == 3 -> + NextIV = random_iv(IV), + L0 = build_cipher_block(BlockSz, Mac, Fragment), + L = [NextIV|L0], + T = Fun(Key, IV, L), {T, CS0#cipher_state{iv=NextIV}}. %%-------------------------------------------------------------------- --spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), tls_version()) -> +-spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), + ssl_record:ssl_version(), boolean()) -> {binary(), binary(), #cipher_state{}} | #alert{}. %% %% 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, _) -> +decipher(?NULL, _HashSz, CipherState, Fragment, _, _) -> {Fragment, <<>>, CipherState}; -decipher(?RC4, HashSz, CipherState, Fragment, _) -> - State0 = case CipherState#cipher_state.state of - undefined -> crypto:rc4_set_key(CipherState#cipher_state.key); - S -> S - end, - try crypto:rc4_encrypt_with_state(State0, Fragment) of +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), #generic_stream_cipher{content = Content, mac = Mac} = GSC, @@ -130,42 +214,57 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) -> %% alerts may permit certain attacks against CBC mode as used in %% TLS [CBCATT]. It is preferable to uniformly use the %% bad_record_mac alert to hide the specific type of the error." - ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed) end; -decipher(?DES, HashSz, CipherState, Fragment, Version) -> +decipher(?DES, HashSz, CipherState, Fragment, Version, PaddingCheck) -> block_decipher(fun(Key, IV, T) -> - crypto:des_cbc_decrypt(Key, IV, T) - end, CipherState, HashSz, Fragment, Version); -decipher(?'3DES', HashSz, CipherState, Fragment, Version) -> + crypto:block_decrypt(des_cbc, Key, IV, T) + end, CipherState, HashSz, Fragment, Version, PaddingCheck); +decipher(?'3DES', HashSz, CipherState, Fragment, Version, PaddingCheck) -> block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) -> - crypto:des3_cbc_decrypt(K1, K2, K3, IV, T) - end, CipherState, HashSz, Fragment, Version); -decipher(?AES, HashSz, CipherState, Fragment, Version) -> + crypto:block_decrypt(des3_cbc, [K1, K2, K3], IV, T) + end, CipherState, HashSz, Fragment, Version, PaddingCheck); +decipher(?AES_CBC, HashSz, CipherState, Fragment, Version, PaddingCheck) -> block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 -> - crypto:aes_cbc_128_decrypt(Key, IV, T); + crypto:block_decrypt(aes_cbc128, Key, IV, T); (Key, IV, T) when byte_size(Key) =:= 32 -> - crypto:aes_cbc_256_decrypt(Key, IV, T) - end, CipherState, HashSz, Fragment, Version). -%% decipher(?IDEA, HashSz, CipherState, Fragment, Version) -> -%% block_decipher(fun(Key, IV, T) -> -%% crypto:idea_cbc_decrypt(Key, IV, T) -%% end, CipherState, HashSz, Fragment, Version); + crypto:block_decrypt(aes_cbc256, Key, IV, T) + end, CipherState, HashSz, Fragment, Version, PaddingCheck). + +%%-------------------------------------------------------------------- +-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 Fun(Key, IV, Fragment) of - Text -> - GBC = generic_block_cipher_from_bin(Text, HashSz), - case is_correct_padding(GBC, Version) of - true -> - Content = GBC#generic_block_cipher.content, - Mac = GBC#generic_block_cipher.mac, - CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)}, - {Content, Mac, CipherState1}; - false -> - ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) - end + HashSz, Fragment, Version, PaddingCheck) -> + try + Text = Fun(Key, IV, Fragment), + NextIV = next_iv(Fragment, IV), + GBC = generic_block_cipher_from_bin(Version, Text, NextIV, HashSz), + Content = GBC#generic_block_cipher.content, + Mac = GBC#generic_block_cipher.mac, + CipherState1 = CipherState0#cipher_state{iv=GBC#generic_block_cipher.next_iv}, + case is_correct_padding(GBC, Version, PaddingCheck) of + true -> + {Content, Mac, CipherState1}; + false -> + %% decryption failed or invalid padding, + %% intentionally break Content to make + %% sure a packet with invalid padding + %% but otherwise correct data will fail + %% the MAC test later + {<<16#F0, Content/binary>>, Mac, CipherState1} + end catch _:_ -> %% This is a DECRYPTION_FAILED but @@ -173,30 +272,175 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, %% alerts may permit certain attacks against CBC mode as used in %% TLS [CBCATT]. It is preferable to uniformly use the %% bad_record_mac alert to hide the specific type of the error." - ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed) 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, decryption_failed) + end + catch + _:_ -> + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed) + end. + %%-------------------------------------------------------------------- --spec suites(tls_version()) -> [cipher_suite()]. +-spec suites(ssl_record:ssl_version()) -> [cipher_suite()]. %% %% Description: Returns a list of supported cipher suites. %%-------------------------------------------------------------------- suites({3, 0}) -> - ssl_ssl3:suites(); -suites({3, N}) when N == 1; N == 2 -> - ssl_tls1:suites(). + ssl_v3:suites(); +suites({3, N}) -> + tls_v1:suites(N); +suites(Version) -> + suites(dtls_v1:corresponding_tls_version(Version)). +all_suites(Version) -> + suites(Version) + ++ anonymous_suites(Version) + ++ psk_suites(Version) + ++ srp_suites() + ++ rc4_suites(Version) + ++ des_suites(Version). %%-------------------------------------------------------------------- --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() -> - [?TLS_DH_anon_WITH_RC4_128_MD5, + +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, + ?TLS_DH_anon_WITH_AES_128_CBC_SHA256, + ?TLS_DH_anon_WITH_AES_256_CBC_SHA256, + ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA, + ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA, + ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, + ?TLS_DH_anon_WITH_RC4_128_MD5]; + +anonymous_suites(2) -> + [?TLS_ECDH_anon_WITH_AES_128_CBC_SHA, + ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA, + ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, ?TLS_DH_anon_WITH_DES_CBC_SHA, + ?TLS_DH_anon_WITH_RC4_128_MD5]; + +anonymous_suites(N) when N == 0; + N == 1 -> + [?TLS_DH_anon_WITH_RC4_128_MD5, ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, - ?TLS_DH_anon_WITH_AES_128_CBC_SHA, - ?TLS_DH_anon_WITH_AES_256_CBC_SHA]. + ?TLS_DH_anon_WITH_DES_CBC_SHA + ]. + +%%-------------------------------------------------------------------- +-spec psk_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()]. +%% +%% Description: Returns a list of the PSK cipher suites, only supported +%% if explicitly set by user. +%%-------------------------------------------------------------------- +psk_suites({3, N}) -> + psk_suites(N); + +psk_suites(N) + when N >= 3 -> + [ + ?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, + ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + ?TLS_PSK_WITH_AES_256_CBC_SHA, + ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + ?TLS_PSK_WITH_AES_128_CBC_SHA, + ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + ?TLS_PSK_WITH_3DES_EDE_CBC_SHA, + ?TLS_DHE_PSK_WITH_RC4_128_SHA, + ?TLS_RSA_PSK_WITH_RC4_128_SHA, + ?TLS_PSK_WITH_RC4_128_SHA]. + +%%-------------------------------------------------------------------- +-spec srp_suites() -> [cipher_suite()]. +%% +%% Description: Returns a list of the SRP cipher suites, only supported +%% if explicitly set by user. +%%-------------------------------------------------------------------- +srp_suites() -> + [?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA]. +%%-------------------------------------------------------------------- +-spec rc4_suites(Version::ssl_record:ssl_version()) -> [cipher_suite()]. +%% +%% Description: Returns a list of the RSA|(ECDH/RSA)| (ECDH/ECDSA) +%% with RC4 cipher suites, only supported if explicitly set by user. +%% Are not considered secure any more. Other RC4 suites already +%% belonged to the user configured only category. +%%-------------------------------------------------------------------- +rc4_suites({3, 0}) -> + [?TLS_RSA_WITH_RC4_128_SHA, + ?TLS_RSA_WITH_RC4_128_MD5]; +rc4_suites({3, N}) when N =< 3 -> + [?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_ECDH_ECDSA_WITH_RC4_128_SHA, + ?TLS_ECDH_RSA_WITH_RC4_128_SHA]. +%%-------------------------------------------------------------------- +-spec des_suites(Version::ssl_record:ssl_version()) -> [cipher_suite()]. +%% +%% Description: Returns a list of the cipher suites +%% with DES cipher, only supported if explicitly set by user. +%% Are not considered secure any more. +%%-------------------------------------------------------------------- +des_suites(_)-> + [?TLS_DHE_RSA_WITH_DES_CBC_SHA, + ?TLS_RSA_WITH_DES_CBC_SHA]. %%-------------------------------------------------------------------- -spec suite_definition(cipher_suite()) -> erl_cipher_suite(). @@ -207,56 +451,315 @@ anonymous_suites() -> %%------------------------------------------------------------------- %% TLS v1.1 suites suite_definition(?TLS_NULL_WITH_NULL_NULL) -> - {null, null, null}; + {null, null, null, null}; +%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension +%% to avoid handshake failure from old servers that do not ignore +%% hello extension data as they should. +suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) -> + {null, null, null, null}; %% suite_definition(?TLS_RSA_WITH_NULL_MD5) -> -%% {rsa, null, md5}; +%% {rsa, null, md5, default_prf}; %% suite_definition(?TLS_RSA_WITH_NULL_SHA) -> -%% {rsa, null, sha}; +%% {rsa, null, sha, default_prf}; suite_definition(?TLS_RSA_WITH_RC4_128_MD5) -> - {rsa, rc4_128, md5}; -suite_definition(?TLS_RSA_WITH_RC4_128_SHA) -> - {rsa, rc4_128, sha}; -%% suite_definition(?TLS_RSA_WITH_IDEA_CBC_SHA) -> -%% {rsa, idea_cbc, sha}; -suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) -> - {rsa, des_cbc, sha}; + {rsa, rc4_128, md5, default_prf}; +suite_definition(?TLS_RSA_WITH_RC4_128_SHA) -> + {rsa, rc4_128, sha, default_prf}; +suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) -> + {rsa, des_cbc, sha, default_prf}; suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) -> - {rsa, '3des_ede_cbc', sha}; + {rsa, '3des_ede_cbc', sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_DES_CBC_SHA) -> - {dhe_dss, des_cbc, sha}; + {dhe_dss, des_cbc, sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) -> - {dhe_dss, '3des_ede_cbc', sha}; + {dhe_dss, '3des_ede_cbc', sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> - {dhe_rsa, des_cbc, sha}; + {dhe_rsa, des_cbc, sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) -> - {dhe_rsa, '3des_ede_cbc', sha}; + {dhe_rsa, '3des_ede_cbc', sha, default_prf}; %%% TSL V1.1 AES suites suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA) -> - {rsa, aes_128_cbc, sha}; + {rsa, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) -> - {dhe_dss, aes_128_cbc, sha}; + {dhe_dss, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) -> - {dhe_rsa, aes_128_cbc, sha}; + {dhe_rsa, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) -> - {rsa, aes_256_cbc, sha}; + {rsa, aes_256_cbc, sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) -> - {dhe_dss, aes_256_cbc, sha}; + {dhe_dss, aes_256_cbc, sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> - {dhe_rsa, aes_256_cbc, sha}; + {dhe_rsa, aes_256_cbc, sha, default_prf}; + +%% TLS v1.2 suites + +%% suite_definition(?TLS_RSA_WITH_NULL_SHA) -> +%% {rsa, null, sha, default_prf}; +suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA256) -> + {rsa, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA256) -> + {rsa, aes_256_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) -> + {dhe_dss, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) -> + {dhe_rsa, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) -> + {dhe_dss, aes_256_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) -> + {dhe_rsa, aes_256_cbc, sha256, default_prf}; + +%% not defined YET: +%% TLS_DH_DSS_WITH_AES_128_CBC_SHA256 DH_DSS AES_128_CBC SHA256 +%% TLS_DH_RSA_WITH_AES_128_CBC_SHA256 DH_RSA AES_128_CBC SHA256 +%% TLS_DH_DSS_WITH_AES_256_CBC_SHA256 DH_DSS AES_256_CBC SHA256 +%% TLS_DH_RSA_WITH_AES_256_CBC_SHA256 DH_RSA AES_256_CBC SHA256 %%% DH-ANON deprecated by TLS spec and not available %%% by default, but good for testing purposes. suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) -> - {dh_anon, rc4_128, md5}; + {dh_anon, rc4_128, md5, default_prf}; suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) -> - {dh_anon, des_cbc, sha}; + {dh_anon, des_cbc, sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) -> - {dh_anon, '3des_ede_cbc', sha}; + {dh_anon, '3des_ede_cbc', sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) -> - {dh_anon, aes_128_cbc, sha}; + {dh_anon, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) -> - {dh_anon, aes_256_cbc, sha}. + {dh_anon, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) -> + {dh_anon, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) -> + {dh_anon, aes_256_cbc, sha256, default_prf}; + +%%% PSK Cipher Suites RFC 4279 + +suite_definition(?TLS_PSK_WITH_RC4_128_SHA) -> + {psk, rc4_128, sha, default_prf}; +suite_definition(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) -> + {psk, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA) -> + {psk, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA) -> + {psk, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_RC4_128_SHA) -> + {dhe_psk, rc4_128, sha, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) -> + {dhe_psk, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) -> + {dhe_psk, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) -> + {dhe_psk, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_RC4_128_SHA) -> + {rsa_psk, rc4_128, sha, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) -> + {rsa_psk, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) -> + {rsa_psk, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) -> + {rsa_psk, aes_256_cbc, sha, default_prf}; + +%%% 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) -> + {psk, aes_256_cbc, sha384, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) -> + {dhe_psk, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) -> + {dhe_psk, aes_256_cbc, sha384, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) -> + {rsa_psk, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) -> + {rsa_psk, aes_256_cbc, sha384, default_prf}; + +suite_definition(?TLS_PSK_WITH_NULL_SHA256) -> + {psk, null, sha256, default_prf}; +suite_definition(?TLS_PSK_WITH_NULL_SHA384) -> + {psk, null, sha384, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA256) -> + {dhe_psk, null, sha256, default_prf}; +suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) -> + {dhe_psk, null, sha384, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA256) -> + {rsa_psk, null, sha256, default_prf}; +suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA384) -> + {rsa_psk, null, sha384, default_prf}; + +%%% SRP Cipher Suites RFC 5054 + +suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) -> + {srp_anon, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) -> + {srp_rsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) -> + {srp_dss, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) -> + {srp_anon, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) -> + {srp_rsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) -> + {srp_dss, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) -> + {srp_anon, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) -> + {srp_rsa, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) -> + {srp_dss, aes_256_cbc, sha, default_prf}; + +%% RFC 4492 EC TLS suites +suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) -> + {ecdh_ecdsa, null, sha, default_prf}; +suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) -> + {ecdh_ecdsa, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) -> + {ecdh_ecdsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) -> + {ecdh_ecdsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) -> + {ecdh_ecdsa, aes_256_cbc, sha, default_prf}; + +suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) -> + {ecdhe_ecdsa, null, sha, default_prf}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) -> + {ecdhe_ecdsa, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) -> + {ecdhe_ecdsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -> + {ecdhe_ecdsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -> + {ecdhe_ecdsa, aes_256_cbc, sha, default_prf}; + +suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) -> + {ecdh_rsa, null, sha, default_prf}; +suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) -> + {ecdh_rsa, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) -> + {ecdh_rsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) -> + {ecdh_rsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) -> + {ecdh_rsa, aes_256_cbc, sha, default_prf}; + +suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) -> + {ecdhe_rsa, null, sha, default_prf}; +suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) -> + {ecdhe_rsa, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) -> + {ecdhe_rsa, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) -> + {ecdhe_rsa, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) -> + {ecdhe_rsa, aes_256_cbc, sha, default_prf}; + +suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) -> + {ecdh_anon, null, sha, default_prf}; +suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) -> + {ecdh_anon, rc4_128, sha, default_prf}; +suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) -> + {ecdh_anon, '3des_ede_cbc', sha, default_prf}; +suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) -> + {ecdh_anon, aes_128_cbc, sha, default_prf}; +suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) -> + {ecdh_anon, aes_256_cbc, sha, default_prf}; + +%% RFC 5289 EC TLS suites +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) -> + {ecdhe_ecdsa, aes_128_cbc, sha256, sha256}; +suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) -> + {ecdhe_ecdsa, aes_256_cbc, sha384, sha384}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) -> + {ecdh_ecdsa, aes_128_cbc, sha256, sha256}; +suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) -> + {ecdh_ecdsa, aes_256_cbc, sha384, sha384}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) -> + {ecdhe_rsa, aes_128_cbc, sha256, sha256}; +suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) -> + {ecdhe_rsa, aes_256_cbc, sha384, 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}; + +%% 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 erl_suite_definition(cipher_suite()) -> erl_cipher_suite(). +%% +%% Description: Return erlang cipher suite definition. Filters last value +%% for now (compatibility reasons). +%%-------------------------------------------------------------------- +erl_suite_definition(S) -> + case suite_definition(S) of + {KeyExchange, Cipher, Hash, default_prf} -> + {KeyExchange, Cipher, Hash}; + Suite -> + Suite + end. %%-------------------------------------------------------------------- -spec suite(erl_cipher_suite()) -> cipher_suite(). @@ -273,8 +776,6 @@ suite({rsa, rc4_128, md5}) -> ?TLS_RSA_WITH_RC4_128_MD5; suite({rsa, rc4_128, sha}) -> ?TLS_RSA_WITH_RC4_128_SHA; -%% suite({rsa, idea_cbc, sha}) -> -%% ?TLS_RSA_WITH_IDEA_CBC_SHA; suite({rsa, des_cbc, sha}) -> ?TLS_RSA_WITH_DES_CBC_SHA; suite({rsa, '3des_ede_cbc', sha}) -> @@ -310,7 +811,244 @@ suite({dhe_dss, aes_256_cbc, sha}) -> suite({dhe_rsa, aes_256_cbc, sha}) -> ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA; suite({dh_anon, aes_256_cbc, sha}) -> - ?TLS_DH_anon_WITH_AES_256_CBC_SHA. + ?TLS_DH_anon_WITH_AES_256_CBC_SHA; + +%% TLS v1.2 suites + +%% suite_definition(?TLS_RSA_WITH_NULL_SHA) -> +%% {rsa, null, sha, sha256}; +suite({rsa, aes_128_cbc, sha256}) -> + ?TLS_RSA_WITH_AES_128_CBC_SHA256; +suite({rsa, aes_256_cbc, sha256}) -> + ?TLS_RSA_WITH_AES_256_CBC_SHA256; +suite({dhe_dss, aes_128_cbc, sha256}) -> + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256; +suite({dhe_rsa, aes_128_cbc, sha256}) -> + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256; +suite({dhe_dss, aes_256_cbc, sha256}) -> + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256; +suite({dhe_rsa, aes_256_cbc, sha256}) -> + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; +suite({dh_anon, aes_128_cbc, sha256}) -> + ?TLS_DH_anon_WITH_AES_128_CBC_SHA256; +suite({dh_anon, aes_256_cbc, sha256}) -> + ?TLS_DH_anon_WITH_AES_256_CBC_SHA256; + +%%% PSK Cipher Suites RFC 4279 + +suite({psk, rc4_128,sha}) -> + ?TLS_PSK_WITH_RC4_128_SHA; +suite({psk, '3des_ede_cbc',sha}) -> + ?TLS_PSK_WITH_3DES_EDE_CBC_SHA; +suite({psk, aes_128_cbc,sha}) -> + ?TLS_PSK_WITH_AES_128_CBC_SHA; +suite({psk, aes_256_cbc,sha}) -> + ?TLS_PSK_WITH_AES_256_CBC_SHA; +suite({dhe_psk, rc4_128,sha}) -> + ?TLS_DHE_PSK_WITH_RC4_128_SHA; +suite({dhe_psk, '3des_ede_cbc',sha}) -> + ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA; +suite({dhe_psk, aes_128_cbc,sha}) -> + ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA; +suite({dhe_psk, aes_256_cbc,sha}) -> + ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA; +suite({rsa_psk, rc4_128,sha}) -> + ?TLS_RSA_PSK_WITH_RC4_128_SHA; +suite({rsa_psk, '3des_ede_cbc',sha}) -> + ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA; +suite({rsa_psk, aes_128_cbc,sha}) -> + ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA; +suite({rsa_psk, aes_256_cbc,sha}) -> + ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA; + +%%% TLS 1.2 PSK Cipher Suites RFC 5487 + +suite({psk, aes_128_gcm, null, sha256}) -> + ?TLS_PSK_WITH_AES_128_GCM_SHA256; +suite({psk, aes_256_gcm, null, sha384}) -> + ?TLS_PSK_WITH_AES_256_GCM_SHA384; +suite({dhe_psk, aes_128_gcm, null, sha256}) -> + ?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256; +suite({dhe_psk, aes_256_gcm, null, sha384}) -> + ?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384; +suite({rsa_psk, aes_128_gcm, null, sha256}) -> + ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256; +suite({rsa_psk, aes_256_gcm, null, sha384}) -> + ?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}) -> + ?TLS_PSK_WITH_AES_256_CBC_SHA384; +suite({dhe_psk, aes_128_cbc, sha256}) -> + ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256; +suite({dhe_psk, aes_256_cbc, sha384}) -> + ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384; +suite({rsa_psk, aes_128_cbc, sha256}) -> + ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256; +suite({rsa_psk, aes_256_cbc, sha384}) -> + ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384; + +suite({psk, null, sha256}) -> + ?TLS_PSK_WITH_NULL_SHA256; +suite({psk, null, sha384}) -> + ?TLS_PSK_WITH_NULL_SHA384; +suite({dhe_psk, null, sha256}) -> + ?TLS_DHE_PSK_WITH_NULL_SHA256; +suite({dhe_psk, null, sha384}) -> + ?TLS_DHE_PSK_WITH_NULL_SHA384; +suite({rsa_psk, null, sha256}) -> + ?TLS_RSA_PSK_WITH_NULL_SHA256; +suite({rsa_psk, null, sha384}) -> + ?TLS_RSA_PSK_WITH_NULL_SHA384; + +%%% SRP Cipher Suites RFC 5054 + +suite({srp_anon, '3des_ede_cbc', sha}) -> + ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA; +suite({srp_rsa, '3des_ede_cbc', sha}) -> + ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA; +suite({srp_dss, '3des_ede_cbc', sha}) -> + ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA; +suite({srp_anon, aes_128_cbc, sha}) -> + ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA; +suite({srp_rsa, aes_128_cbc, sha}) -> + ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA; +suite({srp_dss, aes_128_cbc, sha}) -> + ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA; +suite({srp_anon, aes_256_cbc, sha}) -> + ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA; +suite({srp_rsa, aes_256_cbc, sha}) -> + ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA; +suite({srp_dss, aes_256_cbc, sha}) -> + ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA; + +%%% RFC 4492 EC TLS suites +suite({ecdh_ecdsa, null, sha}) -> + ?TLS_ECDH_ECDSA_WITH_NULL_SHA; +suite({ecdh_ecdsa, rc4_128, sha}) -> + ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA; +suite({ecdh_ecdsa, '3des_ede_cbc', sha}) -> + ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA; +suite({ecdh_ecdsa, aes_128_cbc, sha}) -> + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA; +suite({ecdh_ecdsa, aes_256_cbc, sha}) -> + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA; + +suite({ecdhe_ecdsa, null, sha}) -> + ?TLS_ECDHE_ECDSA_WITH_NULL_SHA; +suite({ecdhe_ecdsa, rc4_128, sha}) -> + ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA; +suite({ecdhe_ecdsa, '3des_ede_cbc', sha}) -> + ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA; +suite({ecdhe_ecdsa, aes_128_cbc, sha}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA; +suite({ecdhe_ecdsa, aes_256_cbc, sha}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA; + +suite({ecdh_rsa, null, sha}) -> + ?TLS_ECDH_RSA_WITH_NULL_SHA; +suite({ecdh_rsa, rc4_128, sha}) -> + ?TLS_ECDH_RSA_WITH_RC4_128_SHA; +suite({ecdh_rsa, '3des_ede_cbc', sha}) -> + ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA; +suite({ecdh_rsa, aes_128_cbc, sha}) -> + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA; +suite({ecdh_rsa, aes_256_cbc, sha}) -> + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA; + +suite({ecdhe_rsa, null, sha}) -> + ?TLS_ECDHE_RSA_WITH_NULL_SHA; +suite({ecdhe_rsa, rc4_128, sha}) -> + ?TLS_ECDHE_RSA_WITH_RC4_128_SHA; +suite({ecdhe_rsa, '3des_ede_cbc', sha}) -> + ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA; +suite({ecdhe_rsa, aes_128_cbc, sha}) -> + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA; +suite({ecdhe_rsa, aes_256_cbc, sha}) -> + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; + +suite({ecdh_anon, null, sha}) -> + ?TLS_ECDH_anon_WITH_NULL_SHA; +suite({ecdh_anon, rc4_128, sha}) -> + ?TLS_ECDH_anon_WITH_RC4_128_SHA; +suite({ecdh_anon, '3des_ede_cbc', sha}) -> + ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA; +suite({ecdh_anon, aes_128_cbc, sha}) -> + ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA; +suite({ecdh_anon, aes_256_cbc, sha}) -> + ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA; + +%%% RFC 5289 EC TLS suites +suite({ecdhe_ecdsa, aes_128_cbc, sha256, sha256}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; +suite({ecdhe_ecdsa, aes_256_cbc, sha384, sha384}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384; +suite({ecdh_ecdsa, aes_128_cbc, sha256, sha256}) -> + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256; +suite({ecdh_ecdsa, aes_256_cbc, sha384, sha384}) -> + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384; +suite({ecdhe_rsa, aes_128_cbc, sha256, sha256}) -> + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256; +suite({ecdhe_rsa, aes_256_cbc, sha384, sha384}) -> + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384; +suite({ecdh_rsa, aes_128_cbc, sha256, sha256}) -> + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256; +suite({ecdh_rsa, aes_256_cbc, sha384, sha384}) -> + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384; + +%% RFC 5288 AES-GCM Cipher Suites +suite({rsa, aes_128_gcm, null, sha256}) -> + ?TLS_RSA_WITH_AES_128_GCM_SHA256; +suite({rsa, aes_256_gcm, null, sha384}) -> + ?TLS_RSA_WITH_AES_256_GCM_SHA384; +suite({dhe_rsa, aes_128_gcm, null, sha256}) -> + ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; +suite({dhe_rsa, aes_256_gcm, null, sha384}) -> + ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384; +suite({dh_rsa, aes_128_gcm, null, sha256}) -> + ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256; +suite({dh_rsa, aes_256_gcm, null, sha384}) -> + ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384; +suite({dhe_dss, aes_128_gcm, null, sha256}) -> + ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256; +suite({dhe_dss, aes_256_gcm, null, sha384}) -> + ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384; +suite({dh_dss, aes_128_gcm, null, sha256}) -> + ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256; +suite({dh_dss, aes_256_gcm, null, sha384}) -> + ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384; +suite({dh_anon, aes_128_gcm, null, sha256}) -> + ?TLS_DH_anon_WITH_AES_128_GCM_SHA256; +suite({dh_anon, aes_256_gcm, null, sha384}) -> + ?TLS_DH_anon_WITH_AES_256_GCM_SHA384; + +%% RFC 5289 ECC AES-GCM Cipher Suites +suite({ecdhe_ecdsa, aes_128_gcm, null, sha256}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; +suite({ecdhe_ecdsa, aes_256_gcm, null, sha384}) -> + ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; +suite({ecdh_ecdsa, aes_128_gcm, null, sha256}) -> + ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256; +suite({ecdh_ecdsa, aes_256_gcm, null, sha384}) -> + ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384; +suite({ecdhe_rsa, aes_128_gcm, null, sha256}) -> + ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; +suite({ecdhe_rsa, aes_256_gcm, null, sha384}) -> + ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; +suite({ecdh_rsa, aes_128_gcm, null, sha256}) -> + ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256; +suite({ecdh_rsa, aes_256_gcm, null, sha384}) -> + ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384; + + +%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites +suite({ecdhe_rsa, chacha20_poly1305, null, sha256}) -> + ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; +suite({ecdhe_ecdsa, chacha20_poly1305, null, sha256}) -> + ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; +suite({dhe_rsa, chacha20_poly1305, null, sha256}) -> + ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. %%-------------------------------------------------------------------- -spec openssl_suite(openssl_cipher_suite()) -> cipher_suite(). @@ -318,6 +1056,18 @@ suite({dh_anon, aes_256_cbc, sha}) -> %% Description: Return TLS cipher suite definition. %%-------------------------------------------------------------------- %% translate constants <-> openssl-strings +openssl_suite("DHE-RSA-AES256-SHA256") -> + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; +openssl_suite("DHE-DSS-AES256-SHA256") -> + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256; +openssl_suite("AES256-SHA256") -> + ?TLS_RSA_WITH_AES_256_CBC_SHA256; +openssl_suite("DHE-RSA-AES128-SHA256") -> + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256; +openssl_suite("DHE-DSS-AES128-SHA256") -> + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256; +openssl_suite("AES128-SHA256") -> + ?TLS_RSA_WITH_AES_128_CBC_SHA256; openssl_suite("DHE-RSA-AES256-SHA") -> ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA; openssl_suite("DHE-DSS-AES256-SHA") -> @@ -336,8 +1086,6 @@ openssl_suite("DHE-DSS-AES128-SHA") -> ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA; openssl_suite("AES128-SHA") -> ?TLS_RSA_WITH_AES_128_CBC_SHA; -%%openssl_suite("IDEA-CBC-SHA") -> -%% ?TLS_RSA_WITH_IDEA_CBC_SHA; openssl_suite("RC4-SHA") -> ?TLS_RSA_WITH_RC4_128_SHA; openssl_suite("RC4-MD5") -> @@ -345,7 +1093,118 @@ openssl_suite("RC4-MD5") -> openssl_suite("EDH-RSA-DES-CBC-SHA") -> ?TLS_DHE_RSA_WITH_DES_CBC_SHA; openssl_suite("DES-CBC-SHA") -> - ?TLS_RSA_WITH_DES_CBC_SHA. + ?TLS_RSA_WITH_DES_CBC_SHA; + +%%% SRP Cipher Suites RFC 5054 + +openssl_suite("SRP-DSS-AES-256-CBC-SHA") -> + ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA; +openssl_suite("SRP-RSA-AES-256-CBC-SHA") -> + ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA; +openssl_suite("SRP-DSS-3DES-EDE-CBC-SHA") -> + ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA; +openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") -> + ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("SRP-DSS-AES-128-CBC-SHA") -> + ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA; +openssl_suite("SRP-RSA-AES-128-CBC-SHA") -> + ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA; + +%% RFC 4492 EC TLS suites +openssl_suite("ECDH-ECDSA-RC4-SHA") -> + ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA; +openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") -> + ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("ECDH-ECDSA-AES128-SHA") -> + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA; +openssl_suite("ECDH-ECDSA-AES256-SHA") -> + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA; + +openssl_suite("ECDHE-ECDSA-RC4-SHA") -> + ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA; +openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") -> + ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("ECDHE-ECDSA-AES128-SHA") -> + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA; +openssl_suite("ECDHE-ECDSA-AES256-SHA") -> + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA; + +openssl_suite("ECDHE-RSA-RC4-SHA") -> + ?TLS_ECDHE_RSA_WITH_RC4_128_SHA; +openssl_suite("ECDHE-RSA-DES-CBC3-SHA") -> + ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("ECDHE-RSA-AES128-SHA") -> + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA; +openssl_suite("ECDHE-RSA-AES256-SHA") -> + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; + +openssl_suite("ECDH-RSA-RC4-SHA") -> + ?TLS_ECDH_RSA_WITH_RC4_128_SHA; +openssl_suite("ECDH-RSA-DES-CBC3-SHA") -> + ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("ECDH-RSA-AES128-SHA") -> + ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA; +openssl_suite("ECDH-RSA-AES256-SHA") -> + ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA; + +%% RFC 5289 EC TLS suites +openssl_suite("ECDHE-ECDSA-AES128-SHA256") -> + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; +openssl_suite("ECDHE-ECDSA-AES256-SHA384") -> + ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384; +openssl_suite("ECDH-ECDSA-AES128-SHA256") -> + ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256; +openssl_suite("ECDH-ECDSA-AES256-SHA384") -> + ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384; +openssl_suite("ECDHE-RSA-AES128-SHA256") -> + ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256; +openssl_suite("ECDHE-RSA-AES256-SHA384") -> + ?TLS_ECDHE_RSA_WITH_AES_256_CBC_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; + +%% 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(). %% @@ -369,8 +1228,6 @@ openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) -> "DHE-DSS-AES128-SHA"; openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA) -> "AES128-SHA"; -%% openssl_suite_name(?TLS_RSA_WITH_IDEA_CBC_SHA) -> -%% "IDEA-CBC-SHA"; openssl_suite_name(?TLS_RSA_WITH_RC4_128_SHA) -> "RC4-SHA"; openssl_suite_name(?TLS_RSA_WITH_RC4_128_MD5) -> @@ -379,6 +1236,150 @@ openssl_suite_name(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> "EDH-RSA-DES-CBC-SHA"; openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) -> "DES-CBC-SHA"; +openssl_suite_name(?TLS_RSA_WITH_NULL_SHA256) -> + "NULL-SHA256"; +openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA256) -> + "AES128-SHA256"; +openssl_suite_name(?TLS_RSA_WITH_AES_256_CBC_SHA256) -> + "AES256-SHA256"; +openssl_suite_name(?TLS_DH_DSS_WITH_AES_128_CBC_SHA256) -> + "DH-DSS-AES128-SHA256"; +openssl_suite_name(?TLS_DH_RSA_WITH_AES_128_CBC_SHA256) -> + "DH-RSA-AES128-SHA256"; +openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) -> + "DHE-DSS-AES128-SHA256"; +openssl_suite_name(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) -> + "DHE-RSA-AES128-SHA256"; +openssl_suite_name(?TLS_DH_DSS_WITH_AES_256_CBC_SHA256) -> + "DH-DSS-AES256-SHA256"; +openssl_suite_name(?TLS_DH_RSA_WITH_AES_256_CBC_SHA256) -> + "DH-RSA-AES256-SHA256"; +openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) -> + "DHE-DSS-AES256-SHA256"; +openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) -> + "DHE-RSA-AES256-SHA256"; + +%%% PSK Cipher Suites RFC 4279 + +openssl_suite_name(?TLS_PSK_WITH_AES_256_CBC_SHA) -> + "PSK-AES256-CBC-SHA"; +openssl_suite_name(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) -> + "PSK-3DES-EDE-CBC-SHA"; +openssl_suite_name(?TLS_PSK_WITH_AES_128_CBC_SHA) -> + "PSK-AES128-CBC-SHA"; +openssl_suite_name(?TLS_PSK_WITH_RC4_128_SHA) -> + "PSK-RC4-SHA"; + +%%% SRP Cipher Suites RFC 5054 + +openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) -> + "SRP-RSA-3DES-EDE-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) -> + "SRP-DSS-3DES-EDE-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) -> + "SRP-RSA-AES-128-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) -> + "SRP-DSS-AES-128-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) -> + "SRP-RSA-AES-256-CBC-SHA"; +openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) -> + "SRP-DSS-AES-256-CBC-SHA"; + +%% RFC 4492 EC TLS suites +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) -> + "ECDH-ECDSA-RC4-SHA"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) -> + "ECDH-ECDSA-DES-CBC3-SHA"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) -> + "ECDH-ECDSA-AES128-SHA"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) -> + "ECDH-ECDSA-AES256-SHA"; + +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) -> + "ECDHE-ECDSA-RC4-SHA"; +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) -> + "ECDHE-ECDSA-DES-CBC3-SHA"; +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -> + "ECDHE-ECDSA-AES128-SHA"; +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -> + "ECDHE-ECDSA-AES256-SHA"; + +openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) -> + "ECDH-RSA-RC4-SHA"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) -> + "ECDH-RSA-DES-CBC3-SHA"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) -> + "ECDH-RSA-AES128-SHA"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) -> + "ECDH-RSA-AES256-SHA"; + +openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) -> + "ECDHE-RSA-RC4-SHA"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) -> + "ECDHE-RSA-DES-CBC3-SHA"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) -> + "ECDHE-RSA-AES128-SHA"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) -> + "ECDHE-RSA-AES256-SHA"; + +%% RFC 5289 EC TLS suites +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) -> + "ECDHE-ECDSA-AES128-SHA256"; +openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) -> + "ECDHE-ECDSA-AES256-SHA384"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) -> + "ECDH-ECDSA-AES128-SHA256"; +openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) -> + "ECDH-ECDSA-AES256-SHA384"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) -> + "ECDHE-RSA-AES128-SHA256"; +openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) -> + "ECDHE-RSA-AES256-SHA384"; +openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) -> + "ECDH-RSA-AES128-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). @@ -386,29 +1387,175 @@ openssl_suite_name(Cipher) -> %%-------------------------------------------------------------------- -spec filter(undefined | binary(), [cipher_suite()]) -> [cipher_suite()]. %% -%% Description: . +%% Description: Select the cipher suites that can be used together with the +%% supplied certificate. (Server side functionality) %%------------------------------------------------------------------- filter(undefined, Ciphers) -> Ciphers; filter(DerCert, Ciphers) -> OtpCert = public_key:pkix_decode_cert(DerCert, otp), SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm, - case ssl_certificate:signature_type(SigAlg#'SignatureAlgorithm'.algorithm) of - rsa -> - filter_rsa(OtpCert, Ciphers -- dsa_signed_suites()); - dsa -> - Ciphers -- rsa_signed_suites() + PubKeyInfo = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo, + PubKeyAlg = PubKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm, + + Ciphers1 = + case ssl_certificate:public_key_type(PubKeyAlg#'PublicKeyAlgorithm'.algorithm) of + rsa -> + filter_keyuse(OtpCert, ((Ciphers -- dsa_signed_suites()) -- ec_keyed_suites()) -- ecdh_suites(), + rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites()); + dsa -> + (Ciphers -- rsa_keyed_suites()) -- ec_keyed_suites(); + ec -> + filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(), + [], ecdhe_ecdsa_suites()) + end, + + case public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm) of + {_, rsa} -> + Ciphers1 -- ecdsa_signed_suites(); + {_, dsa} -> + Ciphers1; + {_, ecdsa} -> + Ciphers1 -- rsa_signed_suites() end. %%-------------------------------------------------------------------- +-spec filter_suites([cipher_suite()]) -> [cipher_suite()]. +%% +%% Description: Filter suites for algorithms supported by crypto. +%%------------------------------------------------------------------- +filter_suites(Suites = [Value|_]) when is_tuple(Value) -> + Algos = crypto:supports(), + Hashs = proplists:get_value(hashs, Algos), + lists:filter(fun({KeyExchange, Cipher, Hash}) -> + is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso + is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso + is_acceptable_hash(Hash, proplists:get_value(hashs, Algos)); + ({KeyExchange, Cipher, Hash, Prf}) -> + is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso + is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso + is_acceptable_hash(Hash, Hashs) andalso + is_acceptable_prf(Prf, Hashs) + end, Suites); + +filter_suites(Suites) -> + Algos = crypto:supports(), + Hashs = proplists:get_value(hashs, Algos), + lists:filter(fun(Suite) -> + {KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite), + is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso + is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso + is_acceptable_hash(Hash, Hashs) andalso + is_acceptable_prf(Prf, Hashs) + end, Suites). + +is_acceptable_keyexchange(KeyExchange, _Algos) when KeyExchange == psk; + KeyExchange == null -> + true; +is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == dh_anon; + KeyExchange == dhe_psk -> + proplists:get_bool(dh, Algos); +is_acceptable_keyexchange(dhe_dss, Algos) -> + proplists:get_bool(dh, Algos) andalso + proplists:get_bool(dss, Algos); +is_acceptable_keyexchange(dhe_rsa, Algos) -> + proplists:get_bool(dh, Algos) andalso + proplists:get_bool(rsa, Algos); +is_acceptable_keyexchange(ecdh_anon, Algos) -> + proplists:get_bool(ecdh, Algos); +is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_ecdsa; + KeyExchange == ecdhe_ecdsa -> + proplists:get_bool(ecdh, Algos) andalso + proplists:get_bool(ecdsa, Algos); +is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_rsa; + KeyExchange == ecdhe_rsa -> + proplists:get_bool(ecdh, Algos) andalso + proplists:get_bool(rsa, Algos); +is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == rsa; + KeyExchange == rsa_psk -> + proplists:get_bool(rsa, Algos); +is_acceptable_keyexchange(srp_anon, Algos) -> + proplists:get_bool(srp, Algos); +is_acceptable_keyexchange(srp_dss, Algos) -> + proplists:get_bool(srp, Algos) andalso + proplists:get_bool(dss, Algos); +is_acceptable_keyexchange(srp_rsa, Algos) -> + proplists:get_bool(srp, Algos) andalso + proplists:get_bool(rsa, Algos); +is_acceptable_keyexchange(_KeyExchange, _Algos) -> + false. + +is_acceptable_cipher(null, _Algos) -> + true; +is_acceptable_cipher(rc4_128, Algos) -> + proplists:get_bool(rc4, Algos); +is_acceptable_cipher(des_cbc, Algos) -> + proplists:get_bool(des_cbc, Algos); +is_acceptable_cipher('3des_ede_cbc', Algos) -> + proplists:get_bool(des3_cbc, Algos); +is_acceptable_cipher(aes_128_cbc, Algos) -> + proplists:get_bool(aes_cbc128, Algos); +is_acceptable_cipher(aes_256_cbc, Algos) -> + proplists:get_bool(aes_cbc256, Algos); +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) -> + proplists:get_bool(Cipher, Algos). + +is_acceptable_hash(null, _Algos) -> + true; +is_acceptable_hash(Hash, Algos) -> + proplists:get_bool(Hash, Algos). + +is_acceptable_prf(default_prf, _) -> + true; +is_acceptable_prf(Prf, Algos) -> + proplists:get_bool(Prf, Algos). + +is_fallback(CipherSuites)-> + lists:member(?TLS_FALLBACK_SCSV, CipherSuites). + + +%%-------------------------------------------------------------------- +-spec random_bytes(integer()) -> binary(). + +%% +%% Description: Generates cryptographically secure random sequence +%%-------------------------------------------------------------------- +random_bytes(N) -> + crypto:strong_rand_bytes(N). + +calc_aad(Type, {MajVer, MinVer}, + #{sequence_number := SeqNo}) -> + <<SeqNo:64/integer, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>. + +calc_mac_hash(Type, Version, + PlainFragment, #{sequence_number := SeqNo, + mac_secret := MacSecret, + security_parameters:= + SecPars}) -> + Length = erlang:iolist_size(PlainFragment), + mac_hash(Version, SecPars#security_parameters.mac_algorithm, + MacSecret, SeqNo, Type, + Length, PlainFragment). + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type, + _Length, _Fragment) -> + <<>>; +mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) -> + ssl_v3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment); +mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) + when N =:= 1; N =:= 2; N =:= 3 -> + tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version, + Length, Fragment). bulk_cipher_algorithm(null) -> ?NULL; -%% Not supported yet -%% bulk_cipher_algorithm(idea_cbc) -> -%% ?IDEA; bulk_cipher_algorithm(rc4_128) -> ?RC4; bulk_cipher_algorithm(des_cbc) -> @@ -417,23 +1564,30 @@ 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 -> ?STREAM; -type(Cipher) when Cipher == idea_cbc; - Cipher == des_cbc; +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; -key_material(Cipher) when Cipher == idea_cbc; - Cipher == rc4_128 -> +key_material(rc4_128) -> 16; key_material(des_cbc) -> 8; @@ -442,19 +1596,27 @@ 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) -> 0; -expanded_key_material(Cipher) when Cipher == idea_cbc; - Cipher == rc4_128 -> +expanded_key_material(rc4_128) -> 16; expanded_key_material(Cipher) when Cipher == des_cbc -> 8; 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. @@ -462,52 +1624,138 @@ effective_key_bits(null) -> 0; effective_key_bits(des_cbc) -> 56; -effective_key_bits(Cipher) when Cipher == idea_cbc; - Cipher == rc4_128; - Cipher == aes_128_cbc -> +effective_key_bits(Cipher) when Cipher == rc4_128; + 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). -block_size(Cipher) when Cipher == idea_cbc; - Cipher == des_cbc; +block_size(Cipher) when Cipher == des_cbc; Cipher == '3des_ede_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. -mac_algorithm(null) -> - ?NULL; -mac_algorithm(md5) -> - ?MD5; -mac_algorithm(sha) -> - ?SHA. +prf_algorithm(default_prf, {3, N}) when N >= 3 -> + ?SHA256; +prf_algorithm(default_prf, {3, _}) -> + ?MD5SHA; +prf_algorithm(Algo, _) -> + hash_algorithm(Algo). + +hash_algorithm(null) -> ?NULL; +hash_algorithm(md5) -> ?MD5; +hash_algorithm(sha) -> ?SHA; %% Only sha always refers to "SHA-1" +hash_algorithm(sha224) -> ?SHA224; +hash_algorithm(sha256) -> ?SHA256; +hash_algorithm(sha384) -> ?SHA384; +hash_algorithm(sha512) -> ?SHA512; +hash_algorithm(?NULL) -> null; +hash_algorithm(?MD5) -> md5; +hash_algorithm(?SHA) -> sha; +hash_algorithm(?SHA224) -> sha224; +hash_algorithm(?SHA256) -> sha256; +hash_algorithm(?SHA384) -> sha384; +hash_algorithm(?SHA512) -> sha512; +hash_algorithm(Other) when is_integer(Other) andalso ((Other >= 7) and (Other =< 223)) -> unassigned; +hash_algorithm(Other) when is_integer(Other) andalso ((Other >= 224) and (Other =< 255)) -> Other. + +sign_algorithm(anon) -> ?ANON; +sign_algorithm(rsa) -> ?RSA; +sign_algorithm(dsa) -> ?DSA; +sign_algorithm(ecdsa) -> ?ECDSA; +sign_algorithm(?ANON) -> anon; +sign_algorithm(?RSA) -> rsa; +sign_algorithm(?DSA) -> dsa; +sign_algorithm(?ECDSA) -> ecdsa; +sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 4) and (Other =< 223)) -> unassigned; +sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 224) and (Other =< 255)) -> Other. hash_size(null) -> 0; hash_size(md5) -> 16; hash_size(sha) -> - 20. + 20; +%% Uncomment when adding cipher suite that needs it +%hash_size(sha224) -> +% 28; +hash_size(sha256) -> + 32; +hash_size(sha384) -> + 48. +%% Uncomment when adding cipher suite that needs it +%hash_size(sha512) -> +% 64. -generic_block_cipher_from_bin(T, HashSize) -> +%% RFC 5246: 6.2.3.2. CBC Block Cipher +%% +%% Implementation note: Canvel et al. [CBCTIME] have demonstrated a +%% timing attack on CBC padding based on the time required to compute +%% the MAC. In order to defend against this attack, implementations +%% MUST ensure that record processing time is essentially the same +%% whether or not the padding is correct. In general, the best way to +%% do this is to compute the MAC even if the padding is incorrect, and +%% only then reject the packet. For instance, if the pad appears to be +%% incorrect, the implementation might assume a zero-length pad and then +%% compute the MAC. This leaves a small timing channel, since MAC +%% performance depends to some extent on the size of the data fragment, +%% but it is not believed to be large enough to be exploitable, due to +%% the large block size of existing MACs and the small size of the +%% timing signal. +%% +%% implementation note: +%% We return the original (possibly invalid) PadLength in any case. +%% An invalid PadLength will be caught by is_correct_padding/2 +%% +generic_block_cipher_from_bin({3, N}, T, IV, HashSize) + when N == 0; N == 1 -> Sz1 = byte_size(T) - 1, - <<_:Sz1/binary, ?BYTE(PadLength)>> = T, + <<_:Sz1/binary, ?BYTE(PadLength0)>> = T, + PadLength = if + PadLength0 >= Sz1 -> 0; + true -> PadLength0 + end, CompressedLength = byte_size(T) - PadLength - 1 - HashSize, <<Content:CompressedLength/binary, Mac:HashSize/binary, - Padding:PadLength/binary, ?BYTE(PadLength)>> = T, + Padding:PadLength/binary, ?BYTE(PadLength0)>> = T, + #generic_block_cipher{content=Content, mac=Mac, + padding=Padding, padding_length=PadLength0, + next_iv = IV}; + +generic_block_cipher_from_bin({3, N}, T, IV, HashSize) + when N == 2; N == 3 -> + Sz1 = byte_size(T) - 1, + <<_:Sz1/binary, ?BYTE(PadLength)>> = T, + IVLength = byte_size(IV), + CompressedLength = byte_size(T) - IVLength - PadLength - 1 - HashSize, + <<NextIV:IVLength/binary, Content:CompressedLength/binary, Mac:HashSize/binary, + Padding:PadLength/binary, ?BYTE(PadLength)>> = T, #generic_block_cipher{content=Content, mac=Mac, - padding=Padding, padding_length=PadLength}. + padding=Padding, padding_length=PadLength, + next_iv = NextIV}. generic_stream_cipher_from_bin(T, HashSz) -> Sz = byte_size(T), @@ -516,18 +1764,21 @@ generic_stream_cipher_from_bin(T, HashSz) -> #generic_stream_cipher{content=Content, mac=Mac}. -is_correct_padding(_, {3, 0}) -> - true; -%% For interoperability reasons we do not check the padding in TLS 1.0 as it -%% is not strictly required and breaks interopability with for instance -%% Google. -is_correct_padding(_, {3, 1}) -> - true; -%% Padding must be check in TLS 1.1 and after -is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _) -> - list_to_binary(lists:duplicate(Len, Len)) == Padding. - - +is_correct_padding(#generic_block_cipher{padding_length = Len, + padding = Padding}, {3, 0}, _) -> + Len == byte_size(Padding); %% Only length check is done in SSL 3.0 spec +%% For interoperability reasons it is possible to disable +%% the padding check when using TLS 1.0, as it is not strictly required +%% in the spec (only recommended), howerver this makes TLS 1.0 vunrable to the Poodle attack +%% so by default this clause will not match +is_correct_padding(GenBlockCipher, {3, 1}, false) -> + is_correct_padding(GenBlockCipher, {3, 0}, false); +%% Padding must be checked in TLS 1.1 and after +is_correct_padding(#generic_block_cipher{padding_length = Len, + padding = Padding}, _, _) -> + Len == byte_size(Padding) andalso + list_to_binary(lists:duplicate(Len, Len)) == Padding. + get_padding(Length, BlockSize) -> get_padding_aux(BlockSize, Length rem BlockSize). @@ -537,6 +1788,10 @@ get_padding_aux(BlockSize, PadLength) -> N = BlockSize - PadLength, {N, list_to_binary(lists:duplicate(N, N))}. +random_iv(IV) -> + IVSz = byte_size(IV), + random_bytes(IVSz). + next_iv(Bin, IV) -> BinSz = byte_size(Bin), IVSz = byte_size(IV), @@ -545,50 +1800,146 @@ next_iv(Bin, IV) -> NextIV. rsa_signed_suites() -> - dhe_rsa_suites() ++ rsa_suites(). + dhe_rsa_suites() ++ rsa_suites() ++ + psk_rsa_suites() ++ srp_rsa_suites() ++ + ecdh_rsa_suites() ++ ecdhe_rsa_suites(). + +rsa_keyed_suites() -> + dhe_rsa_suites() ++ rsa_suites() ++ + psk_rsa_suites() ++ srp_rsa_suites() ++ + ecdhe_rsa_suites(). dhe_rsa_suites() -> - [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, ?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_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, + ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + ?TLS_RSA_PSK_WITH_RC4_128_SHA]. + +srp_rsa_suites() -> + [?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA]. rsa_suites() -> - [?TLS_RSA_WITH_AES_256_CBC_SHA, + [?TLS_RSA_WITH_AES_256_CBC_SHA256, + ?TLS_RSA_WITH_AES_256_CBC_SHA, ?TLS_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_RSA_WITH_AES_128_CBC_SHA256, ?TLS_RSA_WITH_AES_128_CBC_SHA, - %%?TLS_RSA_WITH_IDEA_CBC_SHA, ?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5, - ?TLS_RSA_WITH_DES_CBC_SHA]. - + ?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, + ?TLS_ECDH_RSA_WITH_RC4_128_SHA, + ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + ?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_128_GCM_SHA256, + ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384]. + +ecdhe_rsa_suites() -> + [?TLS_ECDHE_RSA_WITH_NULL_SHA, + ?TLS_ECDHE_RSA_WITH_RC4_128_SHA, + ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + ?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_128_GCM_SHA256, + ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256]. + dsa_signed_suites() -> - dhe_dss_suites(). + dhe_dss_suites() ++ srp_dss_suites(). dhe_dss_suites() -> - [?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + [?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, ?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, + ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA]. + +ec_keyed_suites() -> + ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites() + ++ ecdh_rsa_suites(). + +ecdsa_signed_suites() -> + ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites(). + +ecdh_suites() -> + ecdh_rsa_suites() ++ ecdh_ecdsa_suites(). + +ecdh_ecdsa_suites() -> + [?TLS_ECDH_ECDSA_WITH_NULL_SHA, + ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + ?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_128_GCM_SHA256, + ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384]. + +ecdhe_ecdsa_suites() -> + [?TLS_ECDHE_ECDSA_WITH_NULL_SHA, + ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + ?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_128_GCM_SHA256, + ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256]. -filter_rsa(OtpCert, RsaCiphers) -> +filter_keyuse(OtpCert, Ciphers, Suites, SignSuites) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions, Extensions = ssl_certificate:extensions_list(TBSExtensions), case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of undefined -> - RsaCiphers; + Ciphers; #'Extension'{extnValue = KeyUse} -> - Result = filter_rsa_suites(keyEncipherment, - KeyUse, RsaCiphers, rsa_suites()), - filter_rsa_suites(digitalSignature, - KeyUse, Result, dhe_rsa_suites()) + Result = filter_keyuse_suites(keyEncipherment, + KeyUse, Ciphers, Suites), + filter_keyuse_suites(digitalSignature, + KeyUse, Result, SignSuites) end. -filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) -> +filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) -> case ssl_certificate:is_valid_key_usage(KeyUse, Use) of true -> CipherSuits; false -> - CipherSuits -- RsaSuites + CipherSuits -- Suites end. |
