summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPéter Dimitrov <peterdmv@users.noreply.github.com>2021-06-13 19:43:55 +0200
committerIngela Anderton Andin <ingela@erlang.org>2021-07-19 16:37:22 +0200
commitc33fc9cc9a218bd57d522a56a896efc70abd99a6 (patch)
tree5b610d8d51e3a81cf22da610822d76a456350d75
parent3002f55f409f44122d3a45ac53bfd453e9aa2cb2 (diff)
downloaderlang-c33fc9cc9a218bd57d522a56a896efc70abd99a6.tar.gz
ssl: Fix signature algorithm selection for ECDSA
The signature selection algorithm has been changed to also verify if the client supports signatures using the elliptic curve of the server's public/private key pair. The old algorithm only verified the signature algorithm and the hash algorithm, not taking into account the elliptic curve of the key in the server's certificate. This could result in successful TLS connections with non-standard algorithm combinations in the CertificateVerify message such as ECDSA with secp256r1 and SHA512, when the server's certificate had a public key on an unsupported elliptic curve, signed with a non-ECDSA signature algorithm and hash algorithm combination e.g. RSA with SHA256.
-rw-r--r--lib/ssl/src/ssl_handshake.erl100
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl47
-rw-r--r--lib/ssl/test/property_test/ssl_eqc_chain.erl24
-rw-r--r--lib/ssl/test/ssl_cert_SUITE.erl90
-rw-r--r--lib/ssl/test/ssl_test_lib.erl26
5 files changed, 251 insertions, 36 deletions
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index de5490d232..8375e837e8 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1521,7 +1521,7 @@ select_hashsign({#hash_sign_algos{hash_sign_algos = ClientHashSigns},
Cert, KeyExAlgo, SupportedHashSigns, {Major, Minor})
when Major >= 3 andalso Minor >= 3 ->
ClientSignatureSchemes = get_signature_scheme(ClientSignatureSchemes0),
- {SignAlgo0, Param, PublicKeyAlgo0, _} = get_cert_params(Cert),
+ {SignAlgo0, Param, PublicKeyAlgo0, _, _} = get_cert_params(Cert),
SignAlgo = sign_algo(SignAlgo0),
PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
@@ -1575,7 +1575,7 @@ select_hashsign(#certificate_request{
Cert,
SupportedHashSigns,
{Major, Minor}) when Major >= 3 andalso Minor >= 3->
- {SignAlgo0, Param, PublicKeyAlgo0, _} = get_cert_params(Cert),
+ {SignAlgo0, Param, PublicKeyAlgo0, _, _} = get_cert_params(Cert),
SignAlgo = sign_algo(SignAlgo0),
PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
@@ -1598,7 +1598,7 @@ select_hashsign(#certificate_request{
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)
end;
select_hashsign(#certificate_request{certificate_types = Types}, Cert, _, Version) ->
- {_, _, PublicKeyAlgo0, _} = get_cert_params(Cert),
+ {_, _, PublicKeyAlgo0, _, _} = get_cert_params(Cert),
PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
%% Check cert even for TLS 1.0/1.1
@@ -1615,6 +1615,7 @@ select_hashsign(#certificate_request{certificate_types = Types}, Cert, _, Versio
%% - parameters of the signature algorithm
%% - public key algorithm (key type)
%% - RSA key size in bytes
+%% - Elliptic Curve (public key)
get_cert_params(Cert) ->
#'OTPCertificate'{tbsCertificate = TBSCert,
signatureAlgorithm =
@@ -1630,7 +1631,98 @@ get_cert_params(Cert) ->
_ ->
undefined
end,
- {SignAlgo, Param, PublicKeyAlgo, RSAKeySize}.
+ Curve = get_ec_curve(TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo),
+ {SignAlgo, Param, PublicKeyAlgo, RSAKeySize, Curve}.
+
+get_ec_curve(#'OTPSubjectPublicKeyInfo'{
+ algorithm = #'PublicKeyAlgorithm'{
+ algorithm = ?'id-ecPublicKey',
+ parameters = {namedCurve, ?'secp256r1'}}}) ->
+ secp256r1;
+get_ec_curve(#'OTPSubjectPublicKeyInfo'{
+ algorithm = #'PublicKeyAlgorithm'{
+ algorithm = ?'id-ecPublicKey',
+ parameters = {namedCurve, ?'secp384r1'}}}) ->
+ secp384r1;
+get_ec_curve(#'OTPSubjectPublicKeyInfo'{
+ algorithm = #'PublicKeyAlgorithm'{
+ algorithm = ?'id-ecPublicKey',
+ parameters = {namedCurve, ?'secp521r1'}}}) ->
+ secp521r1;
+get_ec_curve(#'OTPSubjectPublicKeyInfo'{
+ algorithm = #'PublicKeyAlgorithm'{
+ algorithm = ?'id-ecPublicKey',
+ parameters = {ecParameters,
+ #'ECParameters'{curve = #'Curve'{} = Curve,
+ base = Base,
+ order = Order,
+ cofactor = Cofactor}}}}) ->
+ curve_to_atom(Curve, Base, Order, Cofactor);
+get_ec_curve(_) ->
+ unsupported.
+
+curve_to_atom(#'Curve'{
+ a = <<255,255,255,255,0,0,0,1,0,0,0,0,0,0,0,0,
+ 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,252>>,
+ b = <<90,198,53,216,170,58,147,231,179,235,189,85,118,152,134,188,
+ 101,29,6,176,204,83,176,246,59,206,60,62,39,210,96,75>>,
+ seed = <<196,157,54,8,134,231,4,147,106,102,120,225,19,157,38,183,
+ 129,159,126,144>>},
+ <<4,107,23,209,242,225,44,66,71,248,188,230,229,99,164,64,
+ 242,119,3,125,129,45,235,51,160,244,161,57,69,216,152,194,
+ 150,79,227,66,226,254,26,127,155,142,231,235,74,124,15,158,
+ 22,43,206,51,87,107,49,94,206,203,182,64,104,55,191,81,
+ 245>>,
+ 115792089210356248762697446949407573529996955224135760342422259061068512044369,
+ 1
+ ) ->
+ secp256r1;
+curve_to_atom(#'Curve'{
+ a = <<255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,
+ 255,255,255,255,0,0,0,0,0,0,0,0,255,255,255,252>>,
+ b = <<179,49,47,167,226, 62,231,228,152,142,5,107,227,248,45,25,
+ 24,29,156,110,254,129,65,18,3,20,8,143,80,19,135,90,
+ 198,86,57,141,138,46,209,157,42,133,200,237,211,236,42,239>>,
+ seed = <<163,53,146,106,163,25,162,122,29,0,137,106,103,115,164,130,
+ 122,205,172,115>>},
+ <<4,170,135,202,34,190,139,5,55,142,177,199,30,243,32,173,
+ 116,110,29,59,98,139,167,155,152,89,247,65,224,130,84,42,
+ 56,85,2,242,93,191,85,41,108,58,84,94,56,114,118,10,
+ 183,54,23,222,74,150,38,44,111,93,158,152,191,146,146,220,
+ 41,248,244,29,189,40,154,20,124,233,218,49,19,181,240,184,
+ 192,10,96,177,206,29,126,129,157,122,67,29,124,144,234,14,
+ 95>>,
+ 39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643,
+ 1) ->
+ secp384r1;
+curve_to_atom(#'Curve'{
+ a = <<1,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,252>>,
+ b = <<0,81,149,62,185,97,142,28,154,31,146,154,33,160,182,133,
+ 64,238,162,218,114,91,153,179,21,243,184,180,137,145,142,241,
+ 9,225,86,25,57,81,236,126,147,123,22,82,192,189,59,177,
+ 191,7,53,115,223,136,61,44,52,241,239,69,31,212,107,80,
+ 63,0>>,
+ seed = <<208,158,136,0,41,28,184,83,150,204,103,23,57,50,132,170,
+ 160,218,100,186>>},
+ <<4,0,198,133,142,6,183,4,4,233,205,158,62,203,102,35,
+ 149,180,66,156,100,129,57,5,63,181,33,248,40,175,96,107,
+ 77,61,186,161,75,94,119,239,231,89,40,254,29,193,39,162,
+ 255,168,222,51,72,179,193,133,106,66,155,249,126,126,49,194,
+ 229,189,102,1,24,57,41,106,120,154,59,192,4,92,138,95,
+ 180,44,125,27,217,152,245,68,73,87,155,68,104,23,175,189,
+ 23,39,62,102,44,151,238,114,153,94,244,38,64,197,80,185,
+ 1,63,173,7,97,53,60,112,134,162,114,194,64,136,190,148,
+ 118,159,209,102,80>>,
+ 6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449,
+ 1) ->
+ secp521r1;
+curve_to_atom(_, _, _, _) ->
+ unsupported.
select_own_cert([OwnCert| _]) ->
OwnCert;
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index cd9beecb3f..0340960fc8 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -650,13 +650,15 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
Cipher = Maybe(select_cipher_suite(HonorCipherOrder, ClientCiphers, ServerCiphers)),
Groups = Maybe(select_common_groups(ServerGroups, ClientGroups)),
Maybe(validate_client_key_share(ClientGroups, ClientShares)),
- {PublicKeyAlgo, SignAlgo, SignHash, RSAKeySize} = get_certificate_params(Cert),
+ {PublicKeyAlgo, SignAlgo, SignHash, RSAKeySize, Curve} = get_certificate_params(Cert),
%% Check if client supports signature algorithm of server certificate
+ %% TODO: We do validate the signature algorithm and signature hash but we could check
+ %% if the signing cert has a key on a curve supported by the client.
Maybe(check_cert_sign_algo(SignAlgo, SignHash, ClientSignAlgs, ClientSignAlgsCert)),
%% Select signature algorithm (used in CertificateVerify message).
- SelectedSignAlg = Maybe(select_sign_algo(PublicKeyAlgo, RSAKeySize, ClientSignAlgs, ServerSignAlgs)),
+ SelectedSignAlg = Maybe(select_sign_algo(PublicKeyAlgo, RSAKeySize, ClientSignAlgs, ServerSignAlgs, Curve)),
%% Select client public key. If no public key found in ClientShares or
%% ClientShares is empty, trigger HelloRetryRequest as we were able
@@ -1417,10 +1419,10 @@ process_certificate_request(#certificate_request_1_3{
ServerSignAlgsCert = get_signature_scheme_list(
maps:get(signature_algs_cert, Extensions, undefined)),
- {PublicKeyAlgo, SignAlgo, SignHash, MaybeRSAKeySize} = get_certificate_params(Cert),
+ {PublicKeyAlgo, SignAlgo, SignHash, MaybeRSAKeySize, Curve} = get_certificate_params(Cert),
{Ref, Maybe} = maybe(),
try
- SelectedSignAlg = Maybe(select_sign_algo(PublicKeyAlgo, MaybeRSAKeySize, ServerSignAlgs, ClientSignAlgs)),
+ SelectedSignAlg = Maybe(select_sign_algo(PublicKeyAlgo, MaybeRSAKeySize, ServerSignAlgs, ClientSignAlgs, Curve)),
%% Check if server supports signature algorithm of client certificate
case check_cert_sign_algo(SignAlgo, SignHash, ServerSignAlgs, ServerSignAlgsCert) of
ok ->
@@ -2322,11 +2324,11 @@ check_cert_sign_algo(SignAlgo, SignHash, _, ClientSignAlgsCert) ->
%% DSA keys are not supported by TLS 1.3
-select_sign_algo(dsa, _RSAKeySize, _PeerSignAlgs, _OwnSignAlgs) ->
+select_sign_algo(dsa, _RSAKeySize, _PeerSignAlgs, _OwnSignAlgs, _Curve) ->
{error, ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)};
-select_sign_algo(_, _RSAKeySize, [], _) ->
+select_sign_algo(_, _RSAKeySize, [], _, _) ->
{error, ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)};
-select_sign_algo(PublicKeyAlgo, RSAKeySize, [PeerSignAlg|PeerSignAlgs], OwnSignAlgs) ->
+select_sign_algo(PublicKeyAlgo, RSAKeySize, [PeerSignAlg|PeerSignAlgs], OwnSignAlgs, Curve) ->
{_, S, _} = ssl_cipher:scheme_to_components(PeerSignAlg),
%% RSASSA-PKCS1-v1_5 and Legacy algorithms are not defined for use in signed
%% TLS handshake messages: filter sha-1 and rsa_pkcs1.
@@ -2342,25 +2344,35 @@ select_sign_algo(PublicKeyAlgo, RSAKeySize, [PeerSignAlg|PeerSignAlgs], OwnSignA
lists:member(PeerSignAlg, OwnSignAlgs) of
true ->
validate_key_compatibility(PublicKeyAlgo, RSAKeySize,
- [PeerSignAlg|PeerSignAlgs], OwnSignAlgs);
+ [PeerSignAlg|PeerSignAlgs], OwnSignAlgs, Curve);
false ->
- select_sign_algo(PublicKeyAlgo, RSAKeySize, PeerSignAlgs, OwnSignAlgs)
+ select_sign_algo(PublicKeyAlgo, RSAKeySize, PeerSignAlgs, OwnSignAlgs, Curve)
end.
-validate_key_compatibility(PublicKeyAlgo, RSAKeySize, [PeerSignAlg|PeerSignAlgs], OwnSignAlgs)
+validate_key_compatibility(PublicKeyAlgo, RSAKeySize, [PeerSignAlg|PeerSignAlgs], OwnSignAlgs, Curve)
when PublicKeyAlgo =:= rsa orelse
PublicKeyAlgo =:= rsa_pss_pss ->
- case is_rsa_key_compatible(RSAKeySize, PeerSignAlg) of
+ {Hash, Sign, _} = ssl_cipher:scheme_to_components(PeerSignAlg),
+ case (Sign =:= rsa_pss_rsae orelse Sign =:= rsa_pss_pss) andalso
+ is_rsa_key_compatible(RSAKeySize, Hash) of
true ->
{ok, PeerSignAlg};
false ->
- select_sign_algo(PublicKeyAlgo, RSAKeySize, PeerSignAlgs, OwnSignAlgs)
+ select_sign_algo(PublicKeyAlgo, RSAKeySize, PeerSignAlgs, OwnSignAlgs, Curve)
end;
-validate_key_compatibility(_, _, [PeerSignAlg|_], _) ->
+validate_key_compatibility(PublicKeyAlgo, RSAKeySize, [PeerSignAlg|PeerSignAlgs], OwnSignAlgs, Curve)
+ when PublicKeyAlgo =:= ecdsa ->
+ {_ , Sign, PeerCurve} = ssl_cipher:scheme_to_components(PeerSignAlg),
+ case Sign =:= ecdsa andalso Curve =:= PeerCurve of
+ true ->
+ {ok, PeerSignAlg};
+ false ->
+ select_sign_algo(PublicKeyAlgo, RSAKeySize, PeerSignAlgs, OwnSignAlgs, Curve)
+ end;
+validate_key_compatibility(_, _, [PeerSignAlg|_], _, _) ->
{ok, PeerSignAlg}.
-is_rsa_key_compatible(KeySize, SigAlg) ->
- {Hash, _, _} = ssl_cipher:scheme_to_components(SigAlg),
+is_rsa_key_compatible(KeySize, Hash) ->
HashSize = ssl_cipher:hash_size(Hash),
%% OpenSSL crypto lib defines a limit on the size of the random salt
@@ -2382,6 +2394,7 @@ is_rsa_key_compatible(KeySize, SigAlg) ->
do_check_cert_sign_algo(_, _, []) ->
{error, ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)};
do_check_cert_sign_algo(SignAlgo, SignHash, [Scheme|T]) ->
+ %% ECDSA: curve is tied to the hash algorithm e.g. ecdsa_secp256r1_sha256
{Hash, Sign, _Curve} = ssl_cipher:scheme_to_components(Scheme),
case compare_sign_algos(SignAlgo, SignHash, Sign, Hash) of
true ->
@@ -2406,11 +2419,11 @@ compare_sign_algos(_, _, _, _) ->
false.
get_certificate_params(Cert) ->
- {SignAlgo0, Param, SubjectPublicKeyAlgo0, RSAKeySize} =
+ {SignAlgo0, Param, SubjectPublicKeyAlgo0, RSAKeySize, Curve} =
ssl_handshake:get_cert_params(Cert),
{SignHash, SignAlgo} = oids_to_atoms(SignAlgo0, Param),
SubjectPublicKeyAlgo = public_key_algo(SubjectPublicKeyAlgo0),
- {SubjectPublicKeyAlgo, SignAlgo, SignHash, RSAKeySize}.
+ {SubjectPublicKeyAlgo, SignAlgo, SignHash, RSAKeySize, Curve}.
oids_to_atoms(?'id-RSASSA-PSS', #'RSASSA-PSS-params'{maskGenAlgorithm =
#'MaskGenAlgorithm'{algorithm = ?'id-mgf1',
diff --git a/lib/ssl/test/property_test/ssl_eqc_chain.erl b/lib/ssl/test/property_test/ssl_eqc_chain.erl
index e108591776..bf949fdf1b 100644
--- a/lib/ssl/test/property_test/ssl_eqc_chain.erl
+++ b/lib/ssl/test/property_test/ssl_eqc_chain.erl
@@ -259,10 +259,10 @@ extraneous_der_cert_chain_opts(Version, Alg) ->
#{server_config := ServerConf0,
client_config := ClientConf0} = public_key:pkix_test_data(#{server_chain => #{root => SRoot,
intermediates => intermediates(Alg, 1),
- peer => []},
+ peer => peer_key(ecdsa)},
client_chain => #{root => CRoot,
intermediates => intermediates(Alg, 1),
- peer => []}}),
+ peer => peer_key(ecdsa)}}),
{ClientChain, ClientRoot} = extraneous_chain_and_root(ClientConf0, "OTP test client ROOT", 1),
{ServerChain, ServerRoot} = extraneous_chain_and_root(ServerConf0, "OTP test server ROOT", 1),
@@ -280,10 +280,10 @@ extraneous_pem_cert_chain_opts(Version, Alg, PrivDir) ->
#{server_config := ServerConf0,
client_config := ClientConf0} = public_key:pkix_test_data(#{server_chain => #{root => SRoot,
intermediates => intermediates(Alg, 1),
- peer => []},
+ peer => peer_key(ecdsa)},
client_chain => #{root => CRoot,
intermediates => intermediates(Alg, 1),
- peer => []}}),
+ peer => peer_key(ecdsa)}}),
{ClientChain, ClientRoot} = extraneous_chain_and_root(ClientConf0, "OTP test client ROOT", 1),
{ServerChain, ServerRoot} = extraneous_chain_and_root(ServerConf0, "OTP test server ROOT", 1),
@@ -301,10 +301,10 @@ extra_extraneous_der_cert_chain_opts(Version, Alg) ->
#{server_config := ServerConf0,
client_config := ClientConf0} = public_key:pkix_test_data(#{server_chain => #{root => SRoot,
intermediates => intermediates(Alg, 3),
- peer => []},
+ peer => peer_key(ecdsa)},
client_chain => #{root => CRoot,
intermediates => intermediates(Alg, 3),
- peer => []}}),
+ peer => peer_key(ecdsa)}}),
{ClientChain0, ClientRoot0} = extraneous_chain_and_root(ClientConf0, "OTP test client ROOT", 2),
@@ -330,10 +330,10 @@ der_extraneous_and_unorder_chain(Version, Alg) ->
client_config := ClientConf0} =
public_key:pkix_test_data(#{server_chain => #{root => SRoot,
intermediates => intermediates(Alg, 3),
- peer => []},
+ peer => peer_key(ecdsa)},
client_chain => #{root => CRoot,
intermediates => intermediates(Alg, 3),
- peer => []}}),
+ peer => peer_key(ecdsa)}}),
{ClientChain0, ClientRoot0} = chain_and_root(ClientConf0),
{ServerChain0, ServerRoot0} = chain_and_root(ServerConf0),
@@ -370,12 +370,12 @@ chain_and_root(Config) ->
{Chain, Root}.
extraneous_chain_and_root(Config, Name, 1) ->
- #{cert := NewRoot, key := Key} = public_key:pkix_test_root_cert(Name, []),
+ #{cert := NewRoot, key := Key} = public_key:pkix_test_root_cert(Name, root_key(ecdsa)),
{[OwnCert, CA0, OldRoot], OldRoot} = chain_and_root(Config),
CA1 = new_intermediat(CA0, Key),
{[OwnCert, CA1, CA0], NewRoot};
extraneous_chain_and_root(Config, Name, 2) ->
- #{cert := NewRoot, key := Key} = public_key:pkix_test_root_cert(Name, []),
+ #{cert := NewRoot, key := Key} = public_key:pkix_test_root_cert(Name, root_key(ecdsa)),
{[OwnCert, CA0, CA1, CA2, OldRoot], OldRoot} = chain_and_root(Config),
CA3 = new_intermediat(CA2, Key),
{[OwnCert, CA0, CA1, CA2, CA3], NewRoot}.
@@ -411,13 +411,13 @@ create_extraneous_and_unorded([Client, _CCA0, _CCA1, CCA2, _CCA3], [Client, OCCA
{[Client, OCCA0, CCA2, OCCA2, OCROOT, OCCA1], [Server, OSCA0, SCA2, OSCA2, OSROOT, OSCA1]}.
root_key(ecdsa) ->
- []; %% Just generate one
+ [{key,{namedCurve, ?secp256r1}}]; %% Use a curve that will be default supported in all TLS versions
root_key(rsa) ->
%% As rsa keygen is not guaranteed to be fast
[{key, ssl_test_lib:hardcode_rsa_key(6)}].
peer_key(ecdsa) ->
- []; %% Just generate one
+ [{key, {namedCurve, ?secp256r1}}]; %% Use a curve that will be default supported in all TLS versions
peer_key(rsa) ->
%% As rsa keygen is not guaranteed to be fast
[{key, ssl_test_lib:hardcode_rsa_key(6)}].
diff --git a/lib/ssl/test/ssl_cert_SUITE.erl b/lib/ssl/test/ssl_cert_SUITE.erl
index a142115b55..a720b788b0 100644
--- a/lib/ssl/test/ssl_cert_SUITE.erl
+++ b/lib/ssl/test/ssl_cert_SUITE.erl
@@ -113,7 +113,13 @@
hello_retry_client_auth_empty_cert_rejected/0,
hello_retry_client_auth_empty_cert_rejected/1,
basic_rsa_1024/0,
- basic_rsa_1024/1
+ basic_rsa_1024/1,
+ signature_algorithms_bad_curve_secp256r1/0,
+ signature_algorithms_bad_curve_secp256r1/1,
+ signature_algorithms_bad_curve_secp384r1/0,
+ signature_algorithms_bad_curve_secp384r1/1,
+ signature_algorithms_bad_curve_secp521r1/0,
+ signature_algorithms_bad_curve_secp521r1/1
]).
%%--------------------------------------------------------------------
@@ -147,7 +153,10 @@ groups() ->
{rsa_pss_rsae_1_3, [], all_version_tests() ++ rsa_tests() ++ tls_1_3_tests() ++ tls_1_3_rsa_tests()},
{rsa_pss_pss, [], all_version_tests() ++ rsa_tests()},
{rsa_pss_pss_1_3, [], all_version_tests() ++ rsa_tests() ++ tls_1_3_tests() ++ tls_1_3_rsa_tests()},
- {ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()}
+ {ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++
+ [signature_algorithms_bad_curve_secp256r1,
+ signature_algorithms_bad_curve_secp384r1,
+ signature_algorithms_bad_curve_secp521r1]}
].
ssl_protocol_groups() ->
@@ -330,14 +339,38 @@ do_init_per_group(Group, Config) ->
end_per_group(GroupName, Config) ->
ssl_test_lib:end_per_group(GroupName, Config).
+init_per_testcase(signature_algorithms_bad_curve_secp256r1, Config) ->
+ init_rsa_ecdsa_opts(Config, secp256r1);
+init_per_testcase(signature_algorithms_bad_curve_secp384r1, Config) ->
+ init_rsa_ecdsa_opts(Config, secp384r1);
+init_per_testcase(signature_algorithms_bad_curve_secp521r1, Config) ->
+ init_rsa_ecdsa_opts(Config, secp521r1);
init_per_testcase(_TestCase, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 10}),
Config.
-end_per_testcase(_TestCase, Config) ->
+end_per_testcase(_TestCase, Config) ->
Config.
+init_rsa_ecdsa_opts(Config0, Curve) ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_rsa_ecdsa_cert(Config0, Curve),
+ COpts = proplists:get_value(client_rsa_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_ecdsa_opts, Config),
+ [{cert_key_alg, ecdsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, COpts},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))]
+ )];
+ false ->
+ {skip, "Missing EC crypto support"}
+ end.
+
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -1050,6 +1083,57 @@ hello_retry_client_auth_empty_cert_rejected(Config) ->
ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required).
%%--------------------------------------------------------------------
+signature_algorithms_bad_curve_secp256r1() ->
+ [{doc,"TLS 1.3: Test that the the client fails to connect "
+ "if server's certificate has a key using an unsupported curve."}].
+
+signature_algorithms_bad_curve_secp256r1(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, {log_level, debug}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {signature_algs, [ecdsa_secp384r1_sha384,
+ ecdsa_secp521r1_sha512,
+ {sha256,rsa}]}|ClientOpts0],
+
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, insufficient_security).
+
+%%--------------------------------------------------------------------
+signature_algorithms_bad_curve_secp384r1() ->
+ [{doc,"TLS 1.3: Test that the the client fails to connect "
+ "if server's certificate has a key using an unsupported curve."}].
+
+signature_algorithms_bad_curve_secp384r1(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, {log_level, debug}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {signature_algs, [ecdsa_secp256r1_sha256,
+ ecdsa_secp521r1_sha512,
+ {sha256,rsa}]}|ClientOpts0],
+
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, insufficient_security).
+
+%%--------------------------------------------------------------------
+signature_algorithms_bad_curve_secp521r1() ->
+ [{doc,"TLS 1.3: Test that the the client fails to connect "
+ "if server's certificate has a key using an unsupported curve."}].
+
+signature_algorithms_bad_curve_secp521r1(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}, {log_level, debug}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {signature_algs, [ecdsa_secp256r1_sha256,
+ ecdsa_secp384r1_sha384,
+ {sha256,rsa}]}|ClientOpts0],
+
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, insufficient_security).
+
+%%--------------------------------------------------------------------
basic_rsa_1024() ->
[{doc, "TLS 1.3 (Basic): Test if connection can be established using 1024 bits RSA keys in certificates."}].
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 012eb9217e..bb86a675ea 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -158,6 +158,7 @@
make_dsa_cert/1,
make_ecdsa_cert/1,
make_ecdh_rsa_cert/1,
+ make_rsa_ecdsa_cert/2,
make_rsa_cert_chains/3,
make_dsa_cert_chains/3,
make_ecc_cert_chains/3,
@@ -1757,6 +1758,31 @@ make_ecdh_rsa_cert(Config) ->
Config
end.
+make_rsa_ecdsa_cert(Config, Curve) ->
+ CryptoSupport = crypto:supports(),
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)) of
+ true ->
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config),
+ "rsa_ecdsa_" ++ atom_to_list(Curve)]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config),
+ "rsa_ecdsa_" ++ atom_to_list(Curve)]),
+ ClientChain = proplists:get_value(client_chain, Config, default_cert_chain_conf()),
+ ServerChain = proplists:get_value(server_chain, Config, default_cert_chain_conf()),
+ CertChainConf = gen_conf(ecdh_rsa, ecdh_rsa, ClientChain, ServerChain, Curve),
+ GenCertData = public_key:pkix_test_data(CertChainConf),
+ [{server_config, ServerConf},
+ {client_config, ClientConf}] =
+ x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+
+ [{server_rsa_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true} | ServerConf]},
+ {server_rsa_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {verify, verify_peer} | ServerConf]},
+ {client_rsa_ecdsa_opts, ClientConf} | Config];
+ _ ->
+ Config
+ end.
+
+
start_upgrade_server(Args) ->
Node = proplists:get_value(node, Args),
Result = spawn_link(Node, ?MODULE, run_upgrade_server, [Args]),