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.