File 0136-ssl-Relax-requierments-on-keyfile.patch of Package erlang
From c492385a0f077c4d8a2416cd9a15ccbef88e39a9 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Thu, 18 Sep 2025 16:49:40 +0200
Subject: [PATCH] ssl: Relax requierments on keyfile
PR-10046 put to hard requierments on keyfile content.
Closes #10217
Closes #10212
---
lib/ssl/src/ssl_config.erl | 27 ++--
lib/ssl/test/ssl_api_SUITE.erl | 49 ++++++-
.../test/ssl_api_SUITE_data/cert_and_key.pem | 126 ++++++++++++++++++
3 files changed, 187 insertions(+), 15 deletions(-)
create mode 100644 lib/ssl/test/ssl_api_SUITE_data/cert_and_key.pem
diff --git a/lib/ssl/src/ssl_config.erl b/lib/ssl/src/ssl_config.erl
index 79ac6eebb7..e901617211 100644
--- a/lib/ssl/src/ssl_config.erl
+++ b/lib/ssl/src/ssl_config.erl
@@ -390,13 +390,8 @@ init_private_key(undefined, CertKey, DbHandle) ->
KeyFile ->
Password = maps:get(password, CertKey, undefined),
try
- {ok, List} = ssl_manager:cache_pem_file(KeyFile, DbHandle),
- [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
- PKey =:= 'RSAPrivateKey' orelse
- PKey =:= 'DSAPrivateKey' orelse
- PKey =:= 'ECPrivateKey' orelse
- PKey =:= 'PrivateKeyInfo'
- ],
+ {ok, PemEntries} = ssl_manager:cache_pem_file(KeyFile, DbHandle),
+ [PemEntry] = key_entry(PemEntries),
public_key:pem_entry_decode(PemEntry, Password)
catch
_:Reason ->
@@ -2179,17 +2174,18 @@ do_handle_cert_file(File, PemCacheName) ->
handle_key_file(#{keyfile := File} = CertKey, PemCacheName) ->
case file:read_file(File) of
{ok, Pem} ->
- case public_key:pem_decode(Pem) of
+ PemEntries = public_key:pem_decode(Pem),
+ Password = maps:get(password, CertKey, ""),
+ case key_entry(PemEntries) of
[KeyEntry] ->
- Password = maps:get(password, CertKey, ""),
try public_key:pem_entry_decode(KeyEntry, Password) of
Key ->
- handle_key(PemCacheName, File, Key, [KeyEntry])
+ handle_key(PemCacheName, File, Key, PemEntries)
catch _:_ ->
{error, wrong_password}
end;
- Unexpected ->
- {error, {unexpected_content, Unexpected}}
+ _ ->
+ {error, {unexpected_content, {missing_single_key, File}}}
end;
{error, _} = Error ->
Error
@@ -2197,6 +2193,13 @@ handle_key_file(#{keyfile := File} = CertKey, PemCacheName) ->
handle_key_file(_,_) ->
ok.
+key_entry(PemEntries) ->
+ [PemEntry || PemEntry = {PKey, _ , _} <- PemEntries,
+ PKey =:= 'RSAPrivateKey' orelse
+ PKey =:= 'DSAPrivateKey' orelse
+ PKey =:= 'ECPrivateKey' orelse
+ PKey =:= 'PrivateKeyInfo'].
+
handle_key(PemCacheName, File, Key, Content) ->
case check_key(Key) of
ok ->
diff --git a/lib/ssl/test/ssl_api_SUITE.erl b/lib/ssl/test/ssl_api_SUITE.erl
index b7a3307fbf..63bd79ba9c 100644
--- a/lib/ssl/test/ssl_api_SUITE.erl
+++ b/lib/ssl/test/ssl_api_SUITE.erl
@@ -197,7 +197,9 @@
exporter_master_secret_consumed/1,
legacy_prf/0,
legacy_prf/1,
- listen_pem_file_failure/1
+ listen_pem_file_failure/1,
+ same_file_for_key_and_cert/0,
+ same_file_for_key_and_cert/1
]).
%% Apply export
@@ -331,7 +333,8 @@ gen_api_tests() ->
cipher_listing,
export_key_materials,
legacy_prf,
- listen_pem_file_failure
+ listen_pem_file_failure,
+ same_file_for_key_and_cert
].
handshake_paus_tests() ->
@@ -3849,6 +3852,7 @@ listen_pem_file_failure(Config) when is_list(Config) ->
BadDH = filename:join(DataDir, "dHParam-invalid.pem"),
BaseOpts = [{versions, [Version]}, {protocol, tls_or_dtls(Version)}],
NoCACerts = filename:join(DataDir, "nocacerts.pem"),
+ CertAndKey = filename:join(DataDir, "cert_and_key.pem"),
{error, {options, {keyfile, {Key, wrong_password}}}} =
ssl:listen(0, [{certfile, Cert}, {keyfile, Key}] ++ BaseOpts),
{error, {options, {certfile, {Key, no_certs}}}} =
@@ -3870,11 +3874,50 @@ listen_pem_file_failure(Config) when is_list(Config) ->
ssl:listen(0, ServerOpts ++ BaseOpts ++ [{dhfile, BadDH}]);
_ ->
ok
- end.
+ end,
+ %% Shall not fail to have both cert and key in same file
+ {ok, L} = ssl:listen(0, [{certfile, CertAndKey}, {keyfile, CertAndKey}] ++ BaseOpts),
+ ssl:close(L).
+
+%%--------------------------------------------------------------------
+same_file_for_key_and_cert() ->
+ ["Test that it works to put entity cert (can be entity cert chain also) and key in same file"].
+
+same_file_for_key_and_cert(Config) when is_list(Config) ->
+ SHA = sha256,
+ #{client_config := ClientOpts0,
+ server_config := ServerOpts0} = ssl_test_lib:make_cert_chains_der(rsa, [{server_chain,
+ [[{digest, SHA}],
+ [{digest, SHA}],
+ [{digest, SHA}]]},
+ {client_chain,
+ [[{digest, SHA}],
+ [{digest, SHA}],
+ [{digest, SHA}]]}
+ ]),
+ ServerCert = proplists:get_value(cert, ServerOpts0),
+ {SKeyType, SKey} = proplists:get_value(key, ServerOpts0),
+ ClientCert = proplists:get_value(cert, ClientOpts0),
+ {CKeyType, CKey} = proplists:get_value(key, ClientOpts0),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ SCertAndKeyFile = filename:join(PrivDir, "server_cert_and_key.pem"),
+ CCertAndKeyFile = filename:join(PrivDir, "client_cert_and_key.pem"),
+ SPemE = [{'Certificate', ServerCert, not_encrypted}, {SKeyType, SKey, not_encrypted}],
+ CPemE = [{'Certificate', ClientCert, not_encrypted}, {CKeyType, CKey, not_encrypted}],
+ ok = file:write_file(SCertAndKeyFile, public_key:pem_encode(SPemE)),
+ ok = file:write_file(CCertAndKeyFile, public_key:pem_encode(CPemE)),
+ ssl_test_lib:basic_test(replace_cerkey_der_with_file(CCertAndKeyFile, ClientOpts0),
+ replace_cerkey_der_with_file(SCertAndKeyFile, ServerOpts0), Config).
+
%%--------------------------------------------------------------------
%% Internal functions
%%--------------------------------------------------------------------
+replace_cerkey_der_with_file(File, Opts0) ->
+ Opts = proplists:delete(key, proplists:delete(cert, Opts0)),
+ [{certfile, File}, {keyfile, File} | Opts].
+
+
establish_connection(Id, ServerNode, ServerOpts, ClientNode, ClientOpts, Hostname) ->
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
diff --git a/lib/ssl/test/ssl_api_SUITE_data/cert_and_key.pem b/lib/ssl/test/ssl_api_SUITE_data/cert_and_key.pem
new file mode 100644
index 0000000000..6a3e44421f
--- /dev/null
+++ b/lib/ssl/test/ssl_api_SUITE_data/cert_and_key.pem
@@ -0,0 +1,126 @@
+// %CopyrightBegin%
+//
+// SPDX-License-Identifier: BSD-3-Clause
+//
+// Copyright (c) 2010 IETF Trust and the persons identified as the document authors. All rights reserved.
+// Copyright Ericsson AB 2025. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// %CopyrightEnd%
+
+-----BEGIN CERTIFICATE-----
+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
+AAAAABcmOEM=
+-----END CERTIFICATE-----
+
+-----BEGIN PRIVATE KEY-----
+MDQCAQAwCwYJYIZIAWUDBAMRBCKAIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4f
+-----END PRIVATE KEY-----
\ No newline at end of file
--
2.51.0