diff options
Diffstat (limited to 'lib/ssl/src/ssl_cipher.erl')
-rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 183 |
1 files changed, 155 insertions, 28 deletions
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index cf1bec6332..873572e231 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -31,9 +31,10 @@ -include("ssl_cipher.hrl"). -include("ssl_handshake.hrl"). -include("ssl_alert.hrl"). +-include("tls_handshake_1_3.hrl"). -include_lib("public_key/include/public_key.hrl"). --export([security_parameters/2, security_parameters/3, +-export([security_parameters/2, security_parameters/3, security_parameters_1_3/2, cipher_init/3, nonce_seed/2, decipher/6, cipher/5, aead_encrypt/5, aead_decrypt/6, suites/1, all_suites/1, crypto_support_filters/0, chacha_suites/1, anonymous_suites/1, psk_suites/1, psk_suites_anon/1, @@ -42,7 +43,12 @@ filter/3, filter_suites/1, filter_suites/2, hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2, is_fallback/1, random_bytes/1, calc_mac_hash/4, - is_stream_ciphersuite/1]). + is_stream_ciphersuite/1, signature_scheme/1, + scheme_to_components/1, hash_size/1, effective_key_bits/1, + key_material/1]). + +%% RFC 8446 TLS 1.3 +-export([generate_client_shares/1, generate_server_share/1, add_zero_padding/2]). -compile(inline). @@ -83,6 +89,15 @@ security_parameters(Version, CipherSuite, SecParams) -> prf_algorithm = prf_algorithm(PrfHashAlg, Version), hash_size = hash_size(Hash)}. +security_parameters_1_3(SecParams, CipherSuite) -> + #{cipher := Cipher, prf := PrfHashAlg} = + ssl_cipher_format:suite_definition(CipherSuite), + SecParams#security_parameters{ + cipher_suite = CipherSuite, + bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher), + prf_algorithm = PrfHashAlg, %% HKDF hash algorithm + cipher_type = ?AEAD}. + %%-------------------------------------------------------------------- -spec cipher_init(cipher_enum(), binary(), binary()) -> #cipher_state{}. %% @@ -159,7 +174,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, Mac, Fragment, {3, N}) - when N == 2; N == 3 -> + when N == 2; N == 3; N == 4 -> NextIV = random_iv(IV), L0 = build_cipher_block(BlockSz, Mac, Fragment), L = [NextIV|L0], @@ -288,6 +303,8 @@ anonymous_suites({3, N}) -> srp_suites_anon() ++ anonymous_suites(N); anonymous_suites({254, _} = Version) -> dtls_v1:anonymous_suites(Version); +anonymous_suites(4) -> + []; %% Raw public key negotiation may be used instead anonymous_suites(N) when N >= 3 -> psk_suites_anon(N) ++ @@ -322,6 +339,8 @@ anonymous_suites(N) when N == 0; %%-------------------------------------------------------------------- psk_suites({3, N}) -> psk_suites(N); +psk_suites(4) -> + []; %% TODO Add new PSK, PSK_(EC)DHE suites psk_suites(N) when N >= 3 -> [ @@ -412,11 +431,12 @@ rc4_suites({3, Minor}) -> rc4_suites(0) -> [?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5]; -rc4_suites(N) when N =< 3 -> +rc4_suites(N) when N =< 4 -> [?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, ?TLS_ECDHE_RSA_WITH_RC4_128_SHA, ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA, ?TLS_ECDH_RSA_WITH_RC4_128_SHA]. + %%-------------------------------------------------------------------- -spec des_suites(Version::ssl_record:ssl_version()) -> [ssl_cipher_format:cipher_suite()]. %% @@ -451,7 +471,7 @@ rsa_suites(0) -> ?TLS_RSA_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_3DES_EDE_CBC_SHA ]; -rsa_suites(N) when N =< 3 -> +rsa_suites(N) when N =< 4 -> [ ?TLS_RSA_WITH_AES_256_GCM_SHA384, ?TLS_RSA_WITH_AES_256_CBC_SHA256, @@ -550,7 +570,8 @@ crypto_support_filters() -> end]}. is_acceptable_keyexchange(KeyExchange, _Algos) when KeyExchange == psk; - KeyExchange == null -> + KeyExchange == null; + KeyExchange == any -> true; is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == dh_anon; KeyExchange == dhe_psk -> @@ -644,6 +665,28 @@ is_stream_ciphersuite(#{cipher := rc4_128}) -> true; is_stream_ciphersuite(_) -> false. + +-spec hash_size(atom()) -> integer(). +hash_size(null) -> + 0; +%% The AEAD MAC hash size is not used in the context +%% of calculating the master secret. See RFC 5246 Section 6.2.3.3. +hash_size(aead) -> + 0; +hash_size(md5) -> + 16; +hash_size(sha) -> + 20; +%% Uncomment when adding cipher suite that needs it +%hash_size(sha224) -> +% 28; +hash_size(sha256) -> + 32; +hash_size(sha384) -> + 48; +hash_size(sha512) -> + 64. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -653,7 +696,7 @@ mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type, 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 -> + when N =:= 1; N =:= 2; N =:= 3; N =:= 4 -> tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version, Length, Fragment). @@ -801,26 +844,58 @@ 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; -%% The AEAD MAC hash size is not used in the context -%% of calculating the master secret. See RFC 5246 Section 6.2.3.3. -hash_size(aead) -> - 0; -hash_size(md5) -> - 16; -hash_size(sha) -> - 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. + +signature_scheme(rsa_pkcs1_sha256) -> ?RSA_PKCS1_SHA256; +signature_scheme(rsa_pkcs1_sha384) -> ?RSA_PKCS1_SHA384; +signature_scheme(rsa_pkcs1_sha512) -> ?RSA_PKCS1_SHA512; +signature_scheme(ecdsa_secp256r1_sha256) -> ?ECDSA_SECP256R1_SHA256; +signature_scheme(ecdsa_secp384r1_sha384) -> ?ECDSA_SECP384R1_SHA384; +signature_scheme(ecdsa_secp521r1_sha512) -> ?ECDSA_SECP521R1_SHA512; +signature_scheme(rsa_pss_rsae_sha256) -> ?RSA_PSS_RSAE_SHA256; +signature_scheme(rsa_pss_rsae_sha384) -> ?RSA_PSS_RSAE_SHA384; +signature_scheme(rsa_pss_rsae_sha512) -> ?RSA_PSS_RSAE_SHA512; +signature_scheme(ed25519) -> ?ED25519; +signature_scheme(ed448) -> ?ED448; +signature_scheme(rsa_pss_pss_sha256) -> ?RSA_PSS_PSS_SHA256; +signature_scheme(rsa_pss_pss_sha384) -> ?RSA_PSS_PSS_SHA384; +signature_scheme(rsa_pss_pss_sha512) -> ?RSA_PSS_PSS_SHA512; +signature_scheme(rsa_pkcs1_sha1) -> ?RSA_PKCS1_SHA1; +signature_scheme(ecdsa_sha1) -> ?ECDSA_SHA1; +signature_scheme(?RSA_PKCS1_SHA256) -> rsa_pkcs1_sha256; +signature_scheme(?RSA_PKCS1_SHA384) -> rsa_pkcs1_sha384; +signature_scheme(?RSA_PKCS1_SHA512) -> rsa_pkcs1_sha512; +signature_scheme(?ECDSA_SECP256R1_SHA256) -> ecdsa_secp256r1_sha256; +signature_scheme(?ECDSA_SECP384R1_SHA384) -> ecdsa_secp384r1_sha384; +signature_scheme(?ECDSA_SECP521R1_SHA512) -> ecdsa_secp521r1_sha512; +signature_scheme(?RSA_PSS_RSAE_SHA256) -> rsa_pss_rsae_sha256; +signature_scheme(?RSA_PSS_RSAE_SHA384) -> rsa_pss_rsae_sha384; +signature_scheme(?RSA_PSS_RSAE_SHA512) -> rsa_pss_rsae_sha512; +signature_scheme(?ED25519) -> ed25519; +signature_scheme(?ED448) -> ed448; +signature_scheme(?RSA_PSS_PSS_SHA256) -> rsa_pss_pss_sha256; +signature_scheme(?RSA_PSS_PSS_SHA384) -> rsa_pss_pss_sha384; +signature_scheme(?RSA_PSS_PSS_SHA512) -> rsa_pss_pss_sha512; +signature_scheme(?RSA_PKCS1_SHA1) -> rsa_pkcs1_sha1; +signature_scheme(?ECDSA_SHA1) -> ecdsa_sha1; +signature_scheme(_) -> unassigned. +%% TODO: reserved code points? + +scheme_to_components(rsa_pkcs1_sha256) -> {sha256, rsa_pkcs1, undefined}; +scheme_to_components(rsa_pkcs1_sha384) -> {sha384, rsa_pkcs1, undefined}; +scheme_to_components(rsa_pkcs1_sha512) -> {sha512, rsa_pkcs1, undefined}; +scheme_to_components(ecdsa_secp256r1_sha256) -> {sha256, ecdsa, secp256r1}; +scheme_to_components(ecdsa_secp384r1_sha384) -> {sha384, ecdsa, secp384r1}; +scheme_to_components(ecdsa_secp521r1_sha512) -> {sha512, ecdsa, secp521r1}; +scheme_to_components(rsa_pss_rsae_sha256) -> {sha256, rsa_pss_rsae, undefined}; +scheme_to_components(rsa_pss_rsae_sha384) -> {sha384, rsa_pss_rsae, undefined}; +scheme_to_components(rsa_pss_rsae_sha512) -> {sha512, rsa_pss_rsae, undefined}; +scheme_to_components(ed25519) -> {undefined, undefined, undefined}; +scheme_to_components(ed448) -> {undefined, undefined, undefined}; +scheme_to_components(rsa_pss_pss_sha256) -> {sha256, rsa_pss_pss, undefined}; +scheme_to_components(rsa_pss_pss_sha384) -> {sha384, rsa_pss_pss, undefined}; +scheme_to_components(rsa_pss_pss_sha512) -> {sha512, rsa_pss_pss, undefined}; +scheme_to_components(rsa_pkcs1_sha1) -> {sha1, rsa_pkcs1, undefined}; +scheme_to_components(ecdsa_sha1) -> {sha1, ecdsa, undefined}. %% RFC 5246: 6.2.3.2. CBC Block Cipher %% @@ -858,7 +933,7 @@ generic_block_cipher_from_bin({3, N}, T, IV, HashSize) next_iv = IV}; generic_block_cipher_from_bin({3, N}, T, IV, HashSize) - when N == 2; N == 3 -> + when N == 2; N == 3; N == 4 -> Sz1 = byte_size(T) - 1, <<_:Sz1/binary, ?BYTE(PadLength)>> = T, IVLength = byte_size(IV), @@ -1126,3 +1201,55 @@ filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) -> false -> CipherSuits -- Suites end. + +generate_server_share(Group) -> + Key = generate_key_exchange(Group), + #key_share_server_hello{ + server_share = #key_share_entry{ + group = Group, + key_exchange = Key + }}. + +generate_client_shares([]) -> + #key_share_client_hello{client_shares = []}; +generate_client_shares(Groups) -> + generate_client_shares(Groups, []). +%% +generate_client_shares([], Acc) -> + #key_share_client_hello{client_shares = lists:reverse(Acc)}; +generate_client_shares([Group|Groups], Acc) -> + Key = generate_key_exchange(Group), + KeyShareEntry = #key_share_entry{ + group = Group, + key_exchange = Key + }, + generate_client_shares(Groups, [KeyShareEntry|Acc]). + + +generate_key_exchange(secp256r1) -> + public_key:generate_key({namedCurve, secp256r1}); +generate_key_exchange(secp384r1) -> + public_key:generate_key({namedCurve, secp384r1}); +generate_key_exchange(secp521r1) -> + public_key:generate_key({namedCurve, secp521r1}); +generate_key_exchange(x25519) -> + crypto:generate_key(ecdh, x25519); +generate_key_exchange(x448) -> + crypto:generate_key(ecdh, x448); +generate_key_exchange(FFDHE) -> + public_key:generate_key(ssl_dh_groups:dh_params(FFDHE)). + + +%% TODO: Move this functionality to crypto! +%% 7.4.1. Finite Field Diffie-Hellman +%% +%% For finite field groups, a conventional Diffie-Hellman [DH76] +%% computation is performed. The negotiated key (Z) is converted to a +%% byte string by encoding in big-endian form and left-padded with zeros +%% up to the size of the prime. This byte string is used as the shared +%% secret in the key schedule as specified above. +add_zero_padding(Bin, PrimeSize) + when byte_size (Bin) =:= PrimeSize -> + Bin; +add_zero_padding(Bin, PrimeSize) -> + add_zero_padding(<<0, Bin/binary>>, PrimeSize). |