From 95259b5d03391adae64610c02f7457875cf13adf Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 25 Sep 2024 09:39:19 +0200 Subject: [PATCH] ssl: Revert checking of legacy schemes Revert back to original implementation for checking of legacy schemes as it was broken by refactor in OTP-26.2.1 and later only partly fixed as the refactor change how the code was interpreted. Now also add explicit test for these algorithms. --- lib/ssl/src/ssl_cipher.erl | 14 ++- lib/ssl/src/ssl_handshake.erl | 2 +- lib/ssl/src/tls_handshake.erl | 18 +++- lib/ssl/test/ssl_cert_SUITE.erl | 18 ++-- lib/ssl/test/tls_1_3_version_SUITE.erl | 114 ++++++++++++++++++++++++- 5 files changed, 153 insertions(+), 13 deletions(-) diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 18e90c0212a8..c8ceaba4fc6d 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -560,10 +560,20 @@ hash_size(sha384) -> hash_size(sha512) -> 64. -is_supported_sign({Hash, rsa} = SignAlgo, HashSigns) -> +%% Handle RSA and RSA_PSS_RSAE +is_supported_sign({Hash, rsa} = SignAlgo, HashSigns) -> %% ?rsaEncryption cert signalgo used lists:member(SignAlgo, HashSigns) orelse lists:member({Hash, rsa_pss_rsae}, HashSigns); -is_supported_sign(SignAlgo, HashSigns) -> +is_supported_sign(rsa_pkcs1_sha256 = SignAlgo, HashSigns) -> %% TLS-1.3 legacy scheme + lists:member(SignAlgo, HashSigns) orelse + lists:member(rsa_pss_rsae_sha256, HashSigns); +is_supported_sign(rsa_pkcs1_sha384 = SignAlgo, HashSigns) -> %% TLS-1.3 legacy scheme + lists:member(SignAlgo, HashSigns) orelse + lists:member(rsa_pss_rsae_sha384, HashSigns); +is_supported_sign(rsa_pkcs1_sha512 = SignAlgo, HashSigns) -> %% TLS-1.3 legacy scheme + lists:member(SignAlgo, HashSigns) orelse + lists:member(rsa_pss_rsae_sha512, HashSigns); +is_supported_sign(SignAlgo, HashSigns) -> %% Normal case, format (scheme or alg-pair) depends on version lists:member(SignAlgo, HashSigns). signature_scheme(rsa_pkcs1_sha256) -> ?RSA_PKCS1_SHA256; diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 1cf61001b106..519bec936f42 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1918,7 +1918,7 @@ client_signature_schemes(ClientHashSigns, undefined) -> ClientHashSigns; client_signature_schemes(_, #signature_algorithms_cert{ signature_scheme_list = ClientSignatureSchemes}) -> - ClientSignatureSchemes. + ssl_cipher:signature_schemes_1_2(ClientSignatureSchemes). %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl index 52d6f0bbce78..9bcb8772a3a7 100644 --- a/lib/ssl/src/tls_handshake.erl +++ b/lib/ssl/src/tls_handshake.erl @@ -335,13 +335,13 @@ handle_client_hello(Version, Renegotiation) -> case tls_record:is_acceptable_version(Version, Versions) of true -> - SupportedHashSigns = - ssl_handshake:supported_hashsigns(maps:get(signature_algs, SslOpts, undefined)), + SigAlgs = ssl_handshake:supported_hashsigns(maps:get(signature_algs, SslOpts, undefined)), + SigAlgsCert = signature_algs_cert(Version, SslOpts, SigAlgs), Curves = maps:get(elliptic_curves, HelloExt, undefined), ClientHashSigns = get_signature_ext(signature_algs, HelloExt, Version), ClientSignatureSchemes = get_signature_ext(signature_algs_cert, HelloExt, Version), AvailableHashSigns = ssl_handshake:available_signature_algs( - ClientHashSigns, SupportedHashSigns, Version), + ClientHashSigns, SigAlgs, Version), ECCCurve = ssl_handshake:select_curve(Curves, SupportedECCs, ECCOrder), {Type, #session{cipher_suite = CipherSuite, own_certificates = [OwnCert |_]} = Session1} @@ -356,7 +356,7 @@ handle_client_hello(Version, #{key_exchange := KeyExAlg} = ssl_cipher_format:suite_bin_to_map(CipherSuite), case ssl_handshake:select_hashsign({ClientHashSigns, ClientSignatureSchemes}, OwnCert, KeyExAlg, - SupportedHashSigns, + SigAlgsCert, Version) of #alert{} = Alert -> throw(Alert); @@ -372,6 +372,16 @@ handle_client_hello(Version, throw(?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)) end. +signature_algs_cert(Version, SslOpts, SigAlgs) when ?TLS_GTE(Version, ?TLS_1_2) -> + case maps:get(signature_algs_cert, SslOpts, undefined) of + undefined -> + SigAlgs; + SigAlgsCert -> + ssl_handshake:supported_hashsigns(SigAlgsCert) + end; +signature_algs_cert(_,_,_) -> + undefined. + handle_client_hello_extensions(Version, Type, Random, CipherSuites, HelloExt, SslOpts, Session0, ConnectionStates0, Renegotiation, HashSign) -> diff --git a/lib/ssl/test/ssl_cert_SUITE.erl b/lib/ssl/test/ssl_cert_SUITE.erl index 9639e60b7024..2f1dc61227e0 100644 --- a/lib/ssl/test/ssl_cert_SUITE.erl +++ b/lib/ssl/test/ssl_cert_SUITE.erl @@ -399,11 +399,17 @@ do_init_per_group(dsa = Alg, Config0) -> Config = ssl_test_lib:make_dsa_cert(Config0), COpts = proplists:get_value(client_dsa_opts, Config), SOpts = proplists:get_value(server_dsa_opts, Config), + ShaDSA = case Version of + {3, 3} -> + [{signature_algs, [{sha, dsa}]}]; + _ -> + [] + end, [{cert_key_alg, dsa}, {extra_client, ssl_test_lib:sig_algs(Alg, Version) ++ - [{ciphers, ssl_test_lib:dsa_suites(Version)}]}, + [{ciphers, ssl_test_lib:dsa_suites(Version)}] ++ ShaDSA}, {extra_server, ssl_test_lib:sig_algs(Alg, Version) ++ - [{ciphers, ssl_test_lib:dsa_suites(Version)}]} | + [{ciphers, ssl_test_lib:dsa_suites(Version)}] ++ ShaDSA} | lists:delete(cert_key_alg, [{client_cert_opts, COpts}, {server_cert_opts, SOpts} | @@ -1209,13 +1215,15 @@ custom_groups(Config) -> %% of CertificateRequest does not contain the algorithm of the client certificate). %% ssl client sends an empty certificate. unsupported_sign_algo_cert_client_auth() -> - [{doc,"TLS 1.3 (backported to TLS-1.2) : Test client authentication with unsupported signature_algorithm_cert"}]. + [{doc,"TLS 1.3 (backported to TLS-1.2) : Test client authentication with unsupported " + "signature_algorithm_cert"}]. unsupported_sign_algo_cert_client_auth(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config), ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config), ServerOpts = [{verify, verify_peer}, - {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256, rsa_pss_pss_sha256]}, + {signature_algs, + [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256, rsa_pss_pss_sha256]}, %% Skip rsa_pkcs1_sha256! {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]}, {fail_if_no_peer_cert, true}|ServerOpts0], @@ -1224,7 +1232,7 @@ unsupported_sign_algo_cert_client_auth(Config) -> 'tlsv1.3' -> ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required); _ -> - ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, insufficient_security) + ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unsupported_certificate) end. %%-------------------------------------------------------------------- diff --git a/lib/ssl/test/tls_1_3_version_SUITE.erl b/lib/ssl/test/tls_1_3_version_SUITE.erl index aaec5473f573..641039cad2fe 100644 --- a/lib/ssl/test/tls_1_3_version_SUITE.erl +++ b/lib/ssl/test/tls_1_3_version_SUITE.erl @@ -58,6 +58,14 @@ legacy_tls12_server_tls_client/1, tls13_client_tls11_server/0, tls13_client_tls11_server/1, + tls12_legacy_cert_sign/0, + tls12_legacy_cert_sign/1, + tls13_legacy_cert_sign/0, + tls13_legacy_cert_sign/1, + tls13_legacy_cert_sign_with_pss_rsae/0, + tls13_legacy_cert_sign_with_pss_rsae/1, + tls12_legacy_cert_sign_with_pss_rsae/0, + tls12_legacy_cert_sign_with_pss_rsae/1, middle_box_tls13_client/0, middle_box_tls13_client/1, middle_box_tls12_enabled_client/0, @@ -116,7 +124,11 @@ legacy_tests() -> tls10_client_tls_server, tls11_client_tls_server, tls12_client_tls_server, - tls13_client_tls11_server + tls13_client_tls11_server, + tls13_legacy_cert_sign, + tls13_legacy_cert_sign_with_pss_rsae, + tls12_legacy_cert_sign, + tls12_legacy_cert_sign_with_pss_rsae ]. init_per_suite(Config) -> @@ -342,6 +354,67 @@ legacy_tls12_server_tls_client(Config) when is_list(Config) -> | ServerOpts0], ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config). + +tls13_legacy_cert_sign() -> + [{doc,"Test that a TLS 1.3 client can connect to TLS-1.3 server with pkcs1_SHA2 cert"}]. + +tls13_legacy_cert_sign(Config) when is_list(Config) -> + ClientOpts = [{versions, ['tlsv1.3']}, + {signature_algs, rsa_pss_rsae_algs() ++ legacy_rsa_algs()}], + ServerOpts = [{versions, ['tlsv1.3']}, + {signature_algs, rsa_pss_rsae_algs()}, + {signature_algs_cert, legacy_rsa_algs()}], + + test_rsa_pcks1_cert(sha256, ClientOpts, ServerOpts, Config), + test_rsa_pcks1_cert(sha512, ClientOpts, ServerOpts, Config), + test_rsa_pcks1_cert(sha384, ClientOpts, ServerOpts, Config). + +tls13_legacy_cert_sign_with_pss_rsae() -> + [{doc,"Test that a TLS 1.3 enabled client can connect to legacy TLS-1.2 server with legacy pkcs1_SHA2 cert"}]. + +tls13_legacy_cert_sign_with_pss_rsae(Config) when is_list(Config) -> + ClientOpts = [{versions, ['tlsv1.3', 'tlsv1.2']}, + {signature_algs, rsa_pss_rsae_algs()}, + {signature_algs_cert, legacy_rsa_algs()} + ], + ServerOpts = [{versions, ['tlsv1.2']}, + {signature_algs, rsa_pss_rsae_algs()}, + {signature_algs_cert, legacy_rsa_algs()} + ], + + test_rsa_pcks1_cert(sha256, ClientOpts, ServerOpts, Config), + test_rsa_pcks1_cert(sha512, ClientOpts, ServerOpts, Config), + test_rsa_pcks1_cert(sha384, ClientOpts, ServerOpts, Config). + +tls12_legacy_cert_sign() -> + [{doc,"Test that a TLS 1.2 client (with old configuration) can connect to TLS-1.2 server with pkcs1_SHA2 cert"}]. + +tls12_legacy_cert_sign(Config) when is_list(Config) -> + ClientOpts = [{versions, ['tlsv1.2']}, + {signature_algs, rsa_algs()}], + ServerOpts = [{versions, ['tlsv1.2']}, + {signature_algs, rsa_algs()}], + + test_rsa_pcks1_cert(sha256, ClientOpts, ServerOpts, Config), + test_rsa_pcks1_cert(sha512, ClientOpts, ServerOpts, Config), + test_rsa_pcks1_cert(sha384, ClientOpts, ServerOpts, Config). + +tls12_legacy_cert_sign_with_pss_rsae() -> + [{doc,"Test that a modern TLS 1.2 client can connect to TLS-1.2 server with legacy pkcs1_SHA2 cert"}]. + +tls12_legacy_cert_sign_with_pss_rsae(Config) when is_list(Config) -> + ClientOpts = [{versions, ['tlsv1.2']}, + {signature_algs, rsa_pss_rsae_algs() ++ rsa_algs()} + ], + ServerOpts = [{versions, ['tlsv1.2']}, + {signature_algs, rsa_pss_rsae_algs()}, + {signature_algs_cert, legacy_rsa_algs()} + ], + + test_rsa_pcks1_cert(sha256, ClientOpts, ServerOpts, Config), + test_rsa_pcks1_cert(sha512, ClientOpts, ServerOpts, Config), + test_rsa_pcks1_cert(sha384, ClientOpts, ServerOpts, Config). + middle_box_tls13_client() -> [{doc,"Test that a TLS 1.3 client can connect to a 1.3 server with and without middle box compatible mode."}]. middle_box_tls13_client(Config) when is_list(Config) -> @@ -529,3 +602,42 @@ create_bad_client_certfile(NewClientCertFile, ClientOpts) -> ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key), ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]). + +test_rsa_pcks1_cert(SHA, COpts, SOpts, Config) -> + #{client_config := ClientOpts, + server_config := ServerOpts} = public_key:pkix_test_data(#{server_chain => #{root => root_key(SHA), + intermediates => intermediates(SHA, 1), + peer => peer_key(SHA)}, + client_chain => #{root => root_key(SHA), + intermediates => intermediates(SHA, 1), + peer => peer_key(SHA)}}), + ssl_test_lib:basic_test(COpts ++ ClientOpts, SOpts ++ ServerOpts, Config). + +root_key(SHA) -> + %% As rsa keygen is not guaranteed to be fast + [{digest, SHA},{key, ssl_test_lib:hardcode_rsa_key(6)}]. + +peer_key(SHA) -> + %% As rsa keygen is not guaranteed to be fast + [{digest, SHA}, {key, ssl_test_lib:hardcode_rsa_key(5)}]. + +intermediates(SHA, N) when N =< 2 -> + Default = lists:duplicate(N, [{digest, SHA}]), + %% As rsa keygen is not guaranteed to be fast + hardcode_rsa_keys(Default, N, []). + +hardcode_rsa_keys([], 0, Acc) -> + Acc; +hardcode_rsa_keys([Head | Tail], N, Acc) -> + hardcode_rsa_keys(Tail, N-1, [[{key, ssl_test_lib:hardcode_rsa_key(N)} | Head] | Acc]). + + +rsa_algs() -> + [{sha512, rsa}, {sha384, rsa}, {sha256, rsa}]. + +legacy_rsa_algs() -> + [rsa_pkcs1_sha512,rsa_pkcs1_sha384,rsa_pkcs1_sha256]. + +rsa_pss_rsae_algs() -> + [rsa_pss_rsae_sha512,rsa_pss_rsae_sha384,rsa_pss_rsae_sha256]. +