aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src/ssl_cipher.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src/ssl_cipher.erl')
-rw-r--r--lib/ssl/src/ssl_cipher.erl183
1 files changed, 155 insertions, 28 deletions
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index fce48d1678..6e751f9ceb 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, calc_mac_hash/6,
- 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{}.
%%
@@ -158,7 +173,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV, state = IV_Cache0} = CS0,
Mac, Fragment, {3, N})
- when N == 2; N == 3 ->
+ when N == 2; N == 3; N == 4 ->
IV_Size = byte_size(IV),
<<NextIV:IV_Size/binary, IV_Cache/binary>> =
case IV_Cache0 of
@@ -294,6 +309,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) ++
@@ -328,6 +345,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 ->
[
@@ -418,11 +437,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()].
%%
@@ -457,7 +477,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,
@@ -556,7 +576,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 ->
@@ -651,6 +672,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
%%--------------------------------------------------------------------
@@ -660,7 +703,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).
@@ -804,26 +847,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
%%
@@ -861,7 +936,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),
@@ -1159,3 +1234,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).