summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngela Anderton Andin <ingela@erlang.org>2022-02-25 09:22:23 +0100
committerIngela Anderton Andin <ingela@erlang.org>2022-02-28 09:51:23 +0100
commit15023dc182b84b966abb7fec55612adf3263970d (patch)
tree01f123162087cca247cf3e2d318b5b426d893bb6
parentcf698cd8ede551670bd8bb8b231bed67a0f5aa3b (diff)
downloaderlang-15023dc182b84b966abb7fec55612adf3263970d.tar.gz
ssl: Enhance internal configuration handling
When a client has not provided certs or configurations using anonymous cipher suites are enabled use an empty list and empty map to indicate the undefined certificate key pair, so that values are true to the type spec.
-rw-r--r--lib/ssl/src/ssl_certificate.erl4
-rw-r--r--lib/ssl/src/ssl_config.erl6
-rw-r--r--lib/ssl/src/ssl_handshake.erl18
-rw-r--r--lib/ssl/src/tls_dtls_connection.erl17
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl2
5 files changed, 26 insertions, 21 deletions
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 98c6bfe339..cf052e6b0c 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -128,13 +128,13 @@ trusted_cert_and_paths(Chain0, CertDbHandle, CertDbRef, PartialChainHandler) ->
end
end, Paths).
%%--------------------------------------------------------------------
--spec certificate_chain(undefined | binary() | #'OTPCertificate'{} , db_handle(),
+-spec certificate_chain([] | binary() | #'OTPCertificate'{} , db_handle(),
certdb_ref() | {extracted, list()}) ->
{error, no_cert} | {ok, der_cert() | undefined, [der_cert()]}.
%%
%% Description: Return the certificate chain to send to peer.
%%--------------------------------------------------------------------
-certificate_chain(undefined, _, _) ->
+certificate_chain([], _, _) ->
{error, no_cert};
certificate_chain(DerCert, CertDbHandle, CertsDbRef) when is_binary(DerCert) ->
ErlCert = public_key:pkix_decode_cert(DerCert, otp),
diff --git a/lib/ssl/src/ssl_config.erl b/lib/ssl/src/ssl_config.erl
index 65d4259ab4..a65a0a28ff 100644
--- a/lib/ssl/src/ssl_config.erl
+++ b/lib/ssl/src/ssl_config.erl
@@ -141,7 +141,7 @@ init_certificates(#{cacerts := CaCerts,
init_certificates(OwnCerts, Config, CertFile, Role).
init_certificates(undefined, Config, <<>>, _) ->
- {ok, Config, undefined};
+ {ok, Config, [[]]};
init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, client) ->
try
@@ -149,7 +149,7 @@ init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, client
OwnCerts = ssl_certificate:file_to_certificats(CertFile, PemCache),
{ok, Config, OwnCerts}
catch _Error:_Reason ->
- {ok, Config, undefined}
+ {ok, Config, [[]]}
end;
init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, server) ->
@@ -173,7 +173,7 @@ init_private_key(_, #{algorithm := Alg} = Key, _, _Password, _Client) when Alg =
throw({key, {invalid_key_id, Key}})
end;
init_private_key(_, undefined, <<>>, _Password, _Client) ->
- undefined;
+ #{};
init_private_key(DbHandle, undefined, KeyFile, Password, _) ->
try
{ok, List} = ssl_manager:cache_pem_file(KeyFile, DbHandle),
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index ce7fad2bc1..5a6827601f 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -129,30 +129,30 @@ server_hello_done() ->
#server_hello_done{}.
%%--------------------------------------------------------------------
--spec certificate([der_cert()] | undefined, db_handle(), certdb_ref(), client | server) -> #certificate{} | #alert{}.
+-spec certificate([der_cert()], db_handle(), certdb_ref(), client | server) -> #certificate{} | #alert{}.
%%
%% Description: Creates a certificate message.
%%--------------------------------------------------------------------
-certificate(undefined, _, _, client) ->
+certificate([[]], _, _, client) ->
%% If no suitable certificate is available, the client
%% SHOULD send a certificate message containing no
%% certificates. (chapter 7.4.6. RFC 4346)
#certificate{asn1_certificates = []};
certificate([OwnCert], CertDbHandle, CertDbRef, _) ->
- {ok, _, CertChain} = ssl_certificate:certificate_chain(OwnCert, CertDbHandle, CertDbRef),
+ {ok, _, CertChain} = ssl_certificate:certificate_chain(OwnCert, CertDbHandle, CertDbRef),
#certificate{asn1_certificates = CertChain};
certificate([_, _ |_] = Chain, _, _, _) ->
#certificate{asn1_certificates = Chain}.
%%--------------------------------------------------------------------
--spec client_certificate_verify(undefined | der_cert(), binary(),
+-spec client_certificate_verify([der_cert()], binary(),
ssl_record:ssl_version(), term(), public_key:private_key(),
ssl_handshake_history()) ->
#certificate_verify{} | ignore | #alert{}.
%%
%% Description: Creates a certificate_verify message, called by the client.
%%--------------------------------------------------------------------
-client_certificate_verify(undefined, _, _, _, _, _) ->
+client_certificate_verify([[]], _, _, _, _, _) ->
ignore;
client_certificate_verify(_, _, _, _, undefined, _) ->
ignore;
@@ -1073,13 +1073,15 @@ new_session_parameters(SessionId, #session{ecc = ECCCurve0} = Session, CipherSui
cipher_suite = CipherSuite,
compression_method = Compression}.
-%% Possibly support part of "trusted_ca_keys" that corresponds to TLS-1.3 certificate_authorities?!
-select_cert_key_pair_and_params(CipherSuites, [#{private_key := undefined, certs := undefined}], HashSigns, ECCCurve0,
+%% Possibly support part of "trusted_ca_keys" extension that corresponds to TLS-1.3 certificate_authorities?!
+
+select_cert_key_pair_and_params(CipherSuites, [#{private_key := NoKey, certs := [[]] = NoCerts}], HashSigns, ECCCurve0,
#{ciphers := UserSuites, honor_cipher_order := HonorCipherOrder}, Version) ->
+ %% This can happen if anonymous cipher suites are enabled
Suites = available_suites(undefined, UserSuites, Version, HashSigns, ECCCurve0),
CipherSuite0 = select_cipher_suite(CipherSuites, Suites, HonorCipherOrder),
CurveAndSuite = cert_curve(undefined, ECCCurve0, CipherSuite0),
- {[undefined], undefined, CurveAndSuite};
+ {NoCerts, NoKey, CurveAndSuite};
select_cert_key_pair_and_params(CipherSuites, [#{private_key := Key, certs := [Cert | _] = Certs}], HashSigns, ECCCurve0,
#{ciphers := UserSuites, honor_cipher_order := HonorCipherOrder}, Version) ->
Suites = available_suites(Cert, UserSuites, Version, HashSigns, ECCCurve0),
diff --git a/lib/ssl/src/tls_dtls_connection.erl b/lib/ssl/src/tls_dtls_connection.erl
index 8be41a0dd2..7220f9ba1e 100644
--- a/lib/ssl/src/tls_dtls_connection.erl
+++ b/lib/ssl/src/tls_dtls_connection.erl
@@ -408,11 +408,14 @@ certify(internal, #certificate_request{},
certify(internal, #certificate_request{},
#state{static_env = #static_env{role = client,
protocol_cb = Connection},
- connection_env = #connection_env{cert_key_pairs = undefined}} = State) ->
+ session = Session0,
+ connection_env = #connection_env{cert_key_pairs = [#{certs := [[]]}]}} = State) ->
%% The client does not have a certificate and will send an empty reply, the server may fail
%% or accept the connection by its own preference. No signature algorithms needed as there is
%% no certificate to verify.
- Connection:next_event(?FUNCTION_NAME, no_record, State#state{client_certificate_requested = true});
+ Connection:next_event(?FUNCTION_NAME, no_record, State#state{client_certificate_requested = true,
+ session = Session0#session{own_certificates = [[]],
+ private_key = #{}}});
certify(internal, #certificate_request{} = CertRequest,
#state{static_env = #static_env{role = client,
protocol_cb = Connection,
@@ -1639,7 +1642,7 @@ ocsp_info(#{ocsp_expect := no_staple} = OcspState, _, PeerCert) ->
}.
select_client_cert_key_pair(Session0,_,
- [#{private_key := undefined = NoKey, certs := undefined = NoCerts}],
+ [#{private_key := NoKey, certs := [[]] = NoCerts}],
_,_,_,_) ->
%% No certificate supplied : empty certificate will be sent
Session0#session{own_certificates = NoCerts,
@@ -1647,10 +1650,10 @@ select_client_cert_key_pair(Session0,_,
select_client_cert_key_pair(Session0, CertRequest, CertKeyPairs, SupportedHashSigns, TLSVersion, CertDbHandle, CertDbRef) ->
select_client_cert_key_pair(Session0, CertRequest, CertKeyPairs, SupportedHashSigns, TLSVersion, CertDbHandle, CertDbRef, undefined).
-select_client_cert_key_pair(Session0,_,[], _, _,_,_, undefined = Default) ->
- %% No certificate compliant signing algorithms found: empty certificate will be sent
- Session0#session{own_certificates = Default,
- private_key = Default};
+select_client_cert_key_pair(Session0,_,[], _, _,_,_, undefined) ->
+ %% No certificate compliant with signing algorithms found: empty certificate will be sent
+ Session0#session{own_certificates = [[]],
+ private_key = #{}};
select_client_cert_key_pair(_,_,[], _, _,_,_,#session{}=Session) ->
%% No certificate compliant with guide lines send default
Session;
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index 87104d1df4..755f9e407f 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -2995,7 +2995,7 @@ select_server_cert_key_pair(Session, [#{private_key := Key, certs := [Cert| _] =
end.
select_client_cert_key_pair(Session0,
- [#{private_key := undefined = NoKey, certs := undefined = NoCerts}],
+ [#{private_key := NoKey, certs := [[]] = NoCerts}],
_,_,_,_,_,_) ->
%% No certificate supplied : send empty certificate
Session0#session{own_certificates = NoCerts,