File 3171-ssl-public_key-Extended-key-extension-handling.patch of Package erlang
From e7cd7fc40973493096f1582ae9089d87a7e88991 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Mon, 28 Aug 2023 15:48:34 +0200
Subject: [PATCH 1/2] ssl, public_key: Extended key extension handling
---
lib/public_key/src/pubkey_cert.erl | 27 ++++++++++++++++++++
lib/public_key/test/public_key_SUITE.erl | 32 ++++++++++++++++++++++++
lib/ssl/src/ssl_certificate.erl | 30 ++++++++++++++--------
3 files changed, 78 insertions(+), 11 deletions(-)
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index 4d448fd42c..39084f3e76 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -905,6 +905,27 @@ validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-policyConstraints',
validate_extensions(OtpCert, Rest, NewValidationState, ExistBasicCon,
SelfSigned, UserState, VerifyFun);
+validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-extKeyUsage',
+ critical = true,
+ extnValue = KeyUse} = Extension | Rest],
+ ValidationState#path_validation_state{last_cert = false}, ExistBasicCon,
+ SelfSigned, UserState0, VerifyFun) ->
+ UserState =
+ case ext_keyusage_includes_any(KeyUse) of
+ true -> %% CA cert that specifies ?anyExtendedKeyUsage should not be marked critical
+ verify_fun(OtpCert, {bad_cert, invalid_ext_key_usage}, UserState0, VerifyFun);
+ false ->
+ verify_fun(OtpCert, {extension, Extension}, UserState0, VerifyFun);
+ end,
+ validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, SelfSigned,
+ UserState, VerifyFun);
+validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-extKeyUsage',
+ extnValue = KeyUse} = Extension | Rest],
+ ValidationState, ExistBasicCon,
+ SelfSigned, UserState0, VerifyFun) ->
+ UserState = verify_fun(OtpCert, {extension, Ext}, UserState0, VerifyFun),
+ validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, SelfSigned,
+ UserState, VerifyFun);
validate_extensions(OtpCert, [#'Extension'{} = Extension | Rest],
ValidationState, ExistBasicCon,
SelfSigned, UserState0, VerifyFun) ->
@@ -1483,3 +1504,9 @@ verify_options(#'RSASSA-PSS-params'{saltLength = SaltLen,
[{rsa_padding, rsa_pkcs1_pss_padding},
{rsa_pss_saltlen, SaltLen},
{rsa_mgf1_md, HashAlgo}].
+
+
+ext_keyusage_includes_any(KeyUse) when is_list(KeyUse) ->
+ lists:member(?anyExtendedKeyUsage, KeyUse);
+ext_keyusage_includes_any(_) ->
+ false.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 1a779e03bd..0edf3d29c6 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -95,6 +95,8 @@
pkix_path_validation/1,
pkix_path_validation_root_expired/0,
pkix_path_validation_root_expired/1,
+ pkix_ext_key_usage/0,
+ pkix_ext_key_usage/1,
pkix_verify_hostname_cn/1,
pkix_verify_hostname_subjAltName/1,
pkix_verify_hostname_options/1,
@@ -154,6 +156,7 @@ all() ->
pkix_decode_cert,
pkix_path_validation,
pkix_path_validation_root_expired,
+ pkix_ext_key_usage,
pkix_iso_rsa_oid,
pkix_iso_dsa_oid,
pkix_rsa_md2_oid,
@@ -927,6 +930,35 @@ pkix_path_validation_root_expired(Config) when is_list(Config) ->
Peer = proplists:get_value(cert, Conf),
{error, {bad_cert, cert_expired}} = public_key:pkix_path_validation(Root, [ICA, Peer], []).
+pkix_ext_key_usage() ->
+ [{doc, "Extended key usage is usually in end entity certs, may be in CA but should not be critical in such case"}].
+pkix_ext_key_usage(Config) when is_list(Config) ->
+ SRootSpec = public_key:pkix_test_root_cert("OTP test server ROOT", []),
+ CRootSpec = public_key:pkix_test_root_cert("OTP test client ROOT", []),
+
+ FailCAExt = [#'Extension'{extnID = ?'id-ce-extKeyUsage',
+ extnValue = [?'anyExtendedKeyUsage'],
+ critical = true}],
+ CAExt = [#'Extension'{extnID = ?'id-ce-extKeyUsage',
+ extnValue = [?'anyExtendedKeyUsage'],
+ critical = false}],
+
+ #{server_config := SConf,
+ client_config := CConf} = public_key:pkix_test_data(#{server_chain => #{root => SRootSpec,
+ intermediates => [[{extensions, FailCAExt}]],
+ peer => []},
+ client_chain => #{root => CRootSpec,
+ intermediates => [[{extensions, CAExt}]],
+ peer => []}}),
+ [_STRoot, SICA, SRoot] = proplists:get_value(cacerts, SConf),
+ [_CTRoot, CICA, CRoot] = proplists:get_value(cacerts, CConf),
+ SPeer = proplists:get_value(cert, SConf),
+ CPeer = proplists:get_value(cert, CConf),
+
+ {error, {bad_cert, invalid_ext_key_usage}} = public_key:pkix_path_validation(SRoot, [SICA, SPeer], []),
+
+ {ok, _} = public_key:pkix_path_validation(CRoot, [CICA, CPeer], []).
+
%%--------------------------------------------------------------------
%% To generate the PEM file contents:
%%
--
2.35.3