From c3c1be57eca00024d6162416fc4f1c89de1b9d39 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 28 Oct 2024 08:11:08 +0100 Subject: [PATCH 1/2] ssl: Backport cert_auth exclusion option to pre TLS-1.3 --- lib/ssl/src/ssl.erl | 8 ++++++-- lib/ssl/src/ssl_handshake.erl | 21 +++++++++++++-------- lib/ssl/src/tls_dtls_connection.erl | 3 ++- lib/ssl/test/ssl_api_SUITE.erl | 1 + lib/ssl/test/ssl_cert_SUITE.erl | 18 +++++++++++++++++- 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index a2d85a6a25b5..b26a4b91f0cb 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -1991,8 +1991,12 @@ opt_cacerts(UserOpts, #{verify := Verify, log_level := LogLevel, versions := Ver [{verify, verify_peer}, {cacerts, undefined}]), {Where2, CA} = get_opt_bool(certificate_authorities, Role =:= server, UserOpts, Opts), - assert_version_dep(Where2 =:= new, certificate_authorities, Versions, ['tlsv1.3']), - + case Role of + server -> + assert_version_dep(Where2 =:= new, certificate_authorities, Versions, ['tlsv1.3', 'tlsv1.2', 'tlsv1.1', 'tlsv1']); + client -> + assert_version_dep(Where2 =:= new, certificate_authorities, Versions, ['tlsv1.3']) + end, Opts1 = set_opt_new(new, cacertfile, <<>>, CaCertFile, Opts), Opts2 = set_opt_new(Where2, certificate_authorities, Role =:= server, CA, Opts1), Opts2#{cacerts => CaCerts}. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index ecabcb0ffb71..699b8a4e2909 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -48,7 +48,7 @@ %% Create handshake messages -export([hello_request/0, server_hello/4, server_hello_done/0, - certificate/4, client_certificate_verify/6, certificate_request/4, key_exchange/3, + certificate/4, client_certificate_verify/6, certificate_request/5, key_exchange/3, finished/5, next_protocol/1, digitally_signed/5, certificate_authorities/2]). @@ -180,19 +180,24 @@ client_certificate_verify([OwnCert|_], MasterSecret, Version, %%-------------------------------------------------------------------- -spec certificate_request(db_handle(), - certdb_ref(), #hash_sign_algos{}, ssl_record:ssl_version()) -> + certdb_ref(), #hash_sign_algos{}, ssl_record:ssl_version(), boolean()) -> #certificate_request{}. %% %% Description: Creates a certificate_request message, called by the server. %%-------------------------------------------------------------------- -certificate_request(CertDbHandle, CertDbRef, HashSigns, Version) -> +certificate_request(CertDbHandle, CertDbRef, HashSigns, Version, IncludeCertAuths) -> Types = certificate_types(Version), - Authorities = certificate_authorities(CertDbHandle, CertDbRef), + Authorities = case IncludeCertAuths of + true -> + certificate_authorities(CertDbHandle, CertDbRef); + false -> + [] + end, #certificate_request{ - certificate_types = Types, - hashsign_algorithms = HashSigns, - certificate_authorities = Authorities - }. + certificate_types = Types, + hashsign_algorithms = HashSigns, + certificate_authorities = Authorities + }. %%-------------------------------------------------------------------- -spec key_exchange(client | server, ssl_record:ssl_version(), {premaster_secret, binary(), public_key_info()} | diff --git a/lib/ssl/src/tls_dtls_connection.erl b/lib/ssl/src/tls_dtls_connection.erl index 2822e53b7eed..dd21238dd435 100644 --- a/lib/ssl/src/tls_dtls_connection.erl +++ b/lib/ssl/src/tls_dtls_connection.erl @@ -1338,8 +1338,9 @@ request_client_cert(#state{static_env = #static_env{cert_db = CertDbHandle, TLSVersion = ssl:tls_version(Version), HashSigns = ssl_handshake:available_signature_algs(SupportedHashSigns, TLSVersion), + IncludeCertAuths = maps:get(certificate_authorities, Opts, true), Msg = ssl_handshake:certificate_request(CertDbHandle, CertDbRef, - HashSigns, TLSVersion), + HashSigns, TLSVersion, IncludeCertAuths), State = Connection:queue_handshake(Msg, State0), State#state{client_certificate_status = requested}; diff --git a/lib/ssl/test/ssl_api_SUITE.erl b/lib/ssl/test/ssl_api_SUITE.erl index ced5e763fcc3..27ca87aac1bd 100644 --- a/lib/ssl/test/ssl_api_SUITE.erl +++ b/lib/ssl/test/ssl_api_SUITE.erl @@ -2645,6 +2645,7 @@ options_certificate_authorities(_Config) -> ?OK(#{certificate_authorities := true}, [{certificate_authorities, true}], client), ?OK(#{}, [{certificate_authorities, false}], client, [certificate_authorities]), ?OK(#{certificate_authorities := false}, [{certificate_authorities, false}], server), + ?OK(#{certificate_authorities := false}, [{certificate_authorities, false}, {versions, ['tlsv1.2']}], server), ?OK(#{}, [{certificate_authorities, true}], server, [certificate_authorities]), %% Errors diff --git a/lib/ssl/test/ssl_cert_SUITE.erl b/lib/ssl/test/ssl_cert_SUITE.erl index 1fb0f3bba0a7..119f209c6876 100644 --- a/lib/ssl/test/ssl_cert_SUITE.erl +++ b/lib/ssl/test/ssl_cert_SUITE.erl @@ -129,6 +129,8 @@ signature_algorithms_bad_curve_secp521r1/1, server_certificate_authorities_disabled/0, server_certificate_authorities_disabled/1, + legacy_server_certificate_authorities_disabled/0, + legacy_server_certificate_authorities_disabled/1, cert_auth_in_first_ca/0, cert_auth_in_first_ca/1 ]). @@ -205,7 +207,8 @@ tls_1_3_tests() -> pre_tls_1_3_rsa_tests() -> [ - key_auth_ext_sign_only + key_auth_ext_sign_only, + legacy_server_certificate_authorities_disabled ]. rsa_tests() -> @@ -1395,6 +1398,19 @@ server_certificate_authorities_disabled(Config) -> ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required), ssl_test_lib:basic_test(ClientOpts, [{certificate_authorities, false} | ServerOpts], Config). +%%-------------------------------------------------------------------- +legacy_server_certificate_authorities_disabled() -> + [{doc,"Test that code pre TLS-1.3 can send an empty list for certificate authorities in the certificate request" + "will be run and not fail, black box verification is not possible without strict legacy client, but code coverage will show that right thing happens"}]. + +legacy_server_certificate_authorities_disabled(Config) -> + Version = proplists:get_value(version,Config), + ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config), + ssl_test_lib:basic_test([{versions, [Version]} | ClientOpts], [{versions, [Version]}, {verify, verify_peer}, + {fail_if_no_peer_cert, true}, + {certificate_authorities, false} | ServerOpts], Config). + %%-------------------------------------------------------------------- %% Internal functions ----------------------------------------------- %%-------------------------------------------------------------------- From 2410acd487911b54779dc0a893821ea9644b0767 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 28 Oct 2024 11:54:07 +0100 Subject: [PATCH 2/2] ssl: Update documentation --- lib/ssl/doc/src/ssl.xml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index fbfcc9f0fedd..e302324bf9ad 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -1307,9 +1307,15 @@ fun(srp, Username :: binary(), UserState :: term()) -> extension in its certificate request message that will be sent if the option verify is set to verify_peer. Defaults to true.

-

A reason to exclude the extension would be if the server wants to communicate with clients +

If set to false for older TLS versions its corresponding certificate authorities + definition in its certificate request will be set to the empty list instead of + including the appropriate certificate authorities. This has the same affect + as excluding the TLS-1.3 extension. +

+ +

A reason to exclude the certificate authorities would be if the server wants to communicate with clients incapable of sending complete certificate chains that adhere to the - extension, but the server still has the capability to recreate a chain that it can verify.

+ certificate authorities, but the server still has the capability to recreate a chain that it can verify.