Skip to content

Commit 4cf1e02

Browse files
committed
ssl: For TLS-1.2 cert signature must be compatible with cipher suite
In TLS-1.3 this is negotiated separtly
1 parent b365556 commit 4cf1e02

File tree

2 files changed

+51
-15
lines changed

2 files changed

+51
-15
lines changed

lib/ssl/src/ssl_handshake.erl

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,38 +1146,71 @@ server_select_cert_key_pair_and_params(CipherSuites, [#{private_key := NoKey, ce
11461146
CipherSuite0 = select_cipher_suite(CipherSuites, Suites, HonorCipherOrder),
11471147
CurveAndSuite = cert_curve(undefined, ECCCurve0, CipherSuite0),
11481148
{NoCerts, NoKey, CurveAndSuite};
1149-
server_select_cert_key_pair_and_params(CipherSuites, [#{private_key := Key, certs := [Cert | _] = Certs}], HashSigns, ECCCurve0,
1149+
server_select_cert_key_pair_and_params(CipherSuites0, [#{private_key := Key, certs := [Cert | _] = Certs}], HashSigns, ECCCurve0,
11501150
#{ciphers := UserSuites, honor_cipher_order := HonorCipherOrder}, Version) ->
11511151
Suites = available_suites(Cert, UserSuites, Version, HashSigns, ECCCurve0),
1152+
CipherSuites = [ Suite || Suite <- CipherSuites0,
1153+
is_acceptable_cert(Suite, Cert, HashSigns, ssl:tls_version(Version))],
11521154
CipherSuite0 = select_cipher_suite(CipherSuites, Suites, HonorCipherOrder),
11531155
CurveAndSuite = cert_curve(Cert, ECCCurve0, CipherSuite0),
11541156
{Certs, Key, CurveAndSuite};
1155-
server_select_cert_key_pair_and_params(CipherSuites, [#{private_key := Key, certs := [Cert | _] = Certs} | Rest], HashSigns, ECCCurve0,
1157+
server_select_cert_key_pair_and_params(CipherSuites0, [#{private_key := Key, certs := [Cert | _] = Certs} | Rest], HashSigns, ECCCurve0,
11561158
#{ciphers := UserSuites, honor_cipher_order := HonorCipherOrder} = Opts, Version) ->
11571159
Suites = available_suites(Cert, UserSuites, Version, HashSigns, ECCCurve0),
1160+
CipherSuites = [ Suite || Suite <- CipherSuites0, is_acceptable_cert(Suite, Cert, HashSigns, ssl:tls_version(Version))],
11581161
case select_cipher_suite(CipherSuites, Suites, HonorCipherOrder) of
11591162
no_suite ->
1160-
server_select_cert_key_pair_and_params(CipherSuites, Rest, HashSigns, ECCCurve0, Opts, Version);
1163+
server_select_cert_key_pair_and_params(CipherSuites0, Rest, HashSigns, ECCCurve0, Opts, Version);
11611164
CipherSuite0 ->
1162-
case is_acceptable_cert(Cert, HashSigns, ssl:tls_version(Version)) of
1163-
true ->
1164-
CurveAndSuite = cert_curve(Cert, ECCCurve0, CipherSuite0),
1165-
{Certs, Key, CurveAndSuite};
1166-
false ->
1167-
server_select_cert_key_pair_and_params(CipherSuites, Rest, HashSigns, ECCCurve0, Opts, Version)
1168-
end
1165+
CurveAndSuite = cert_curve(Cert, ECCCurve0, CipherSuite0),
1166+
{Certs, Key, CurveAndSuite}
11691167
end.
11701168

1171-
is_acceptable_cert(Cert, HashSigns, Version)
1169+
is_acceptable_cert(CipherSuite, Cert, HashSigns, Version)
11721170
when ?TLS_1_X(Version),
11731171
?TLS_GTE(Version, ?TLS_1_2) ->
11741172
{SignAlgo0, Param, _, _, _} = get_cert_params(Cert),
11751173
SignAlgo = sign_algo(SignAlgo0, Param),
1176-
is_acceptable_hash_sign(SignAlgo, HashSigns);
1177-
is_acceptable_cert(_,_,_) ->
1174+
is_acceptable_hash_sign(SignAlgo, acceptable_hash_signs(CipherSuite, HashSigns));
1175+
is_acceptable_cert(_, _,_,_) ->
11781176
%% Not negotiable pre TLS-1.2. So if cert is available for version it is acceptable
11791177
true.
11801178

1179+
acceptable_hash_signs(CipherSuite, HashSigns) ->
1180+
#{key_exchange := Kex} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
1181+
Filter = fun({_, rsa_pss_pss}) when Kex == ecdh_rsa;
1182+
Kex == ecdhe_rsa;
1183+
Kex == dhe_rsa;
1184+
Kex == srp_rsa;
1185+
Kex == rsa_psk ->
1186+
1187+
true;
1188+
({_, rsa_pss_rsae}) when Kex == ecdh_rsa;
1189+
Kex == ecdhe_rsa;
1190+
Kex == dhe_rsa;
1191+
Kex == srp_rsa;
1192+
Kex == rsa_psk ->
1193+
true;
1194+
({_, rsa}) when Kex == ecdh_rsa;
1195+
Kex == ecdhe_rsa;
1196+
Kex == dhe_rsa;
1197+
Kex == srp_rsa;
1198+
Kex == rsa_psk;
1199+
Kex == rsa->
1200+
true;
1201+
({_, ecdsa}) when Kex == ecdh_ecdsa;
1202+
Kex == ecdhe_ecdsa ->
1203+
true;
1204+
({_, dsa}) when Kex == dhe_dss;
1205+
Kex == srp_dss ->
1206+
true;
1207+
(_) when Kex == any ->
1208+
true;
1209+
(_) ->
1210+
false
1211+
end,
1212+
[HS || HS <- HashSigns, Filter(HS)].
1213+
11811214
premaster_secret(OtherPublicDhKey, MyPrivateKey, #'DHParameter'{} = Params) ->
11821215
try
11831216
public_key:compute_key(OtherPublicDhKey, MyPrivateKey, Params)
@@ -3658,8 +3691,11 @@ handle_srp_extension(undefined, Session) ->
36583691
handle_srp_extension(#srp{username = Username}, Session) ->
36593692
Session#session{srp_username = Username}.
36603693

3694+
is_acceptable_hash_sign({SHA, rsa} = Algos, SupportedHashSigns) ->
3695+
lists:member({SHA, rsa_pss_rsae}, SupportedHashSigns) orelse
3696+
lists:member(Algos, SupportedHashSigns);
36613697
is_acceptable_hash_sign(Algos, SupportedHashSigns) ->
3662-
lists:member(Algos, SupportedHashSigns).
3698+
lists:member(Algos, SupportedHashSigns).
36633699

36643700
is_acceptable_cert_type(Sign, Types) ->
36653701
lists:member(sign_type(Sign), binary_to_list(Types)).

lib/ssl/src/tls_handshake.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ handle_client_hello(Version,
351351
AvailableHashSigns,
352352
SessIdTracker, Session0#session{ecc = ECCCurve},
353353
Version, SslOpts, CertKeyPairs),
354-
case CipherSuite of
354+
case CipherSuite of
355355
no_suite ->
356356
throw(?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_ciphers));
357357
_ ->

0 commit comments

Comments
 (0)