Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:25
erlang
0552-Gracefully-handle-bad-validity-dates-in-pu...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0552-Gracefully-handle-bad-validity-dates-in-public_key-p.patch of Package erlang
From 97d4036194846d880295398f7ceb81a86c750cda Mon Sep 17 00:00:00 2001 From: Andrea Santambrogio <andreasanta@meta.com> Date: Wed, 18 Oct 2023 16:31:30 +0200 Subject: [PATCH] Gracefully handle bad validity dates in public_key:pkix_path_validation --- lib/public_key/doc/src/public_key.xml | 3 + lib/public_key/src/pubkey_cert.erl | 44 +++++++-- lib/public_key/src/public_key.erl | 2 +- lib/public_key/test/public_key_SUITE.erl | 41 ++++++++- .../bad_date_certchain.pem | 89 +++++++++++++++++++ 5 files changed, 167 insertions(+), 12 deletions(-) create mode 100644 lib/public_key/test/public_key_SUITE_data/bad_date_certchain.pem diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index c726b17595..5fc2420fab 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -641,6 +641,9 @@ fun(OtpCert :: #'OTPCertificate'{}, <tag>{revoked, crl_reason()}</tag> <item><p>Certificate has been revoked.</p></item> + <tag>invalid_validity_dates</tag> + <item><p>The validity section of the X.509 certificate(s) contains invalid date formats not matching the RFC.</p></item> + <tag>atom()</tag> <item><p>Application-specific error reason that is to be checked by the <c>verify_fun</c>.</p></item> </taglist> diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index 879e4e7fd1..4a91335e0c 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -148,19 +148,47 @@ validate_policy_tree(OtpCert, %% current time. %%-------------------------------------------------------------------- validate_time(OtpCert, UserState, VerifyFun) -> + % Parse and check validity of the certificate dates, and if it fails, invoke `verify_fun` to + % hand over control to the caller in order to decide what to do. + case parse_and_check_validity_dates(OtpCert) of + expired -> + % Certificate has correctly formatted dates but it's expired + verify_fun(OtpCert, {bad_cert, cert_expired}, UserState, VerifyFun); + error -> + % Certificate has incorrectly formatted dates, attempt to delegate decision to app function + verify_fun(OtpCert, {bad_cert, invalid_validity_dates}, UserState, VerifyFun); + % Validation succeded and certificate is not expired, no new state needed + ok -> + UserState + end. + +-spec parse_and_check_validity_dates(#'OTPCertificate'{}) -> ok | expired | error. +%% +%% Description: Determines if the passed certificate consains correctly +%% formatted dates in the validity field. If so, it checks if the certificate +%% is not expired. Otherwise, it returns error. +%%-------------------------------------------------------------------- +parse_and_check_validity_dates(OtpCert) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, {'Validity', NotBeforeStr, NotAfterStr} = TBSCert#'OTPTBSCertificate'.validity, Now = calendar:datetime_to_gregorian_seconds(calendar:universal_time()), - NotBefore = time_str_2_gregorian_sec(notBefore, NotBeforeStr), - NotAfter = time_str_2_gregorian_sec(notAfter, NotAfterStr), - - case ((NotBefore =< Now) and (Now =< NotAfter)) of - true -> - UserState; - false -> - verify_fun(OtpCert, {bad_cert, cert_expired}, UserState, VerifyFun) + try + NotBefore = time_str_2_gregorian_sec(notBefore, NotBeforeStr), + NotAfter = time_str_2_gregorian_sec(notAfter, NotAfterStr), + + % Expiration check + if + ((NotBefore =< Now) and (Now =< NotAfter)) -> ok; + true -> expired + end + + % "error:function_clause" is thrown by time_str_2_gregorian_sec if the date format is not valid + % verify_fun only throws exceptions + catch error:function_clause -> + error end. + %%-------------------------------------------------------------------- -spec validate_issuer(#'OTPCertificate'{}, term(), term(), fun()) -> term() | no_return(). %% diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index c05c307ae4..858860e29c 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -163,7 +163,7 @@ -type cert_id() :: {SerialNr::integer(), issuer_name()} . -type issuer_name() :: {rdnSequence,[[#'AttributeTypeAndValue'{}]]} . -type bad_cert_reason() :: cert_expired | invalid_issuer | invalid_signature | name_not_permitted | missing_basic_constraint | invalid_key_usage | duplicate_cert_in_path | - {'policy_requirement_not_met', term()} | {'invalid_policy_mapping', term()} | {revoked, crl_reason()} | atom(). + {'policy_requirement_not_met', term()} | {'invalid_policy_mapping', term()} | {revoked, crl_reason()} | invalid_validity_dates | atom(). -type combined_cert() :: #cert{}. -type cert() :: der_cert() | otp_cert(). diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index d80a8449cc..35aedf0aa5 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -23,6 +23,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). +-include_lib("eunit/include/eunit.hrl"). -export([ suite/0, @@ -97,6 +98,8 @@ pkix_path_validation_root_expired/1, pkix_ext_key_usage/0, pkix_ext_key_usage/1, + pkix_path_validation_bad_date/0, + pkix_path_validation_bad_date/1, pkix_verify_hostname_cn/1, pkix_verify_hostname_subjAltName/1, pkix_verify_hostname_options/1, @@ -159,6 +162,7 @@ all() -> pkix_path_validation, pkix_path_validation_root_expired, pkix_ext_key_usage, + pkix_path_validation_bad_date, pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_dsa_sha2_oid, @@ -193,9 +197,9 @@ groups() -> init_per_suite(Config) -> application:stop(crypto), try crypto:start() of - ok -> - application:start(asn1), - Config + ok -> + application:start(asn1), + Config catch _:_ -> {skip, "Crypto did not start"} end. @@ -966,6 +970,37 @@ pkix_ext_key_usage(Config) when is_list(Config) -> {ok, _} = public_key:pkix_path_validation(CRoot, [CICA, CPeer], []). +pkix_path_validation_bad_date() -> + [{doc, "Ensure bad date formats in `validity` are handled gracefully by verify fun"}]. +pkix_path_validation_bad_date(Config) when is_list(Config) -> + % Load PEM certchain from file + DataDir = proplists:get_value(data_dir, Config), + {ok, Bin} = file:read_file(filename:join(DataDir,"bad_date_certchain.pem")), + + % Decode and extract raw der encoded certificates + CertificateList = public_key:pem_decode(Bin), + [Root | CertificateChain] = lists:map(fun({'Certificate', Der, _}) -> Der end, CertificateList), + + % First test error `invalid_validity_dates` being returned correctly without `verify_fun` override + {error, {bad_cert, invalid_validity_dates}} = public_key:pkix_path_validation(Root, CertificateChain, []), + + % Then test no exception thrown if verify_fun function traps the date error + {ok, _} = public_key:pkix_path_validation(Root, CertificateChain, [ + {verify_fun, % This is the same as ?DEFAULT_VERIFYFUN, but it handles `invalid_validity_dates` gracefully. + {fun + % Test if we can successfully override `invalid_validity_dates` + (_, {bad_cert, invalid_validity_dates}, UserState) -> + {valid, UserState}; + (_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid_peer, UserState) -> + {valid, UserState}; + (_, valid, UserState) -> + {valid, UserState} + end, []} + } + ]). + %%-------------------------------------------------------------------- %% To generate the PEM file contents: %% diff --git a/lib/public_key/test/public_key_SUITE_data/bad_date_certchain.pem b/lib/public_key/test/public_key_SUITE_data/bad_date_certchain.pem new file mode 100644 index 0000000000..6b9cdd1f59 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/bad_date_certchain.pem @@ -0,0 +1,89 @@ +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV +BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYy +ODUyWjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS +Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7 +tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj +nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq +C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ +oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O +JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg +sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi +igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M +RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E +aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um +AGMCAwEAAaOBpjCBozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR/8aTMnqTxIwHwYD +VR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cHM6Ly9hbmRyb2lk +Lmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZIhvcNAQELBQAD +ggIBACDIw41L3KlXG0aMiS//cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB +Pb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw/E53Rbf86qhxKaiAHOjpvAy5Y3m00m +qC0w/Zwvju1twb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG/6ibYCv7rY +DBJDcR9W62BW9jfIoBQcxUCUJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPm +QUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhuKug2jITV0QkXvaJWF4nUaHOTNA4u +JU9WDvZLI1j83A+/xnAJUucIv/zGJ1AMH2boHqF8CY16LpsYgBt6tKxxWH00XcyD +CdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR/OukXrNLfkQ79Iy +ZohZbvabO/X+MVT3rriAoKc8oE2Uws6DF+60PV7/WIPjNvXySdqspImSN78mflxD +qwLqRBYkA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23Uaic +MDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1 +wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID0TCCAbmgAwIBAgIKA4gmZ2BliZaF2jANBgkqhkiG9w0BAQsFADAbMRkwFwYD +VQQFExBmOTIwMDllODUzYjZiMDQ1MB4XDTE5MDQxOTIwMzUxOVoXDTI5MDQxNjIw +MzUxOVowKTEZMBcGA1UEBRMQMWRmNGUwNmE2YzQyZjY1MTEMMAoGA1UEDAwDVEVF +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdg8tZ4Tz9D9IFMefEvOM+s+nLky2cm1b +dTjvgiVkG4LMKAWle7EyW3wnh810aPohcFgYBrBvKCZlmjz8NMv/SxRBYWGO/7No +vnT/HLOi0e3Eeos1eg+bS9TLY9m8r1kmo4G2MIGzMB0GA1UdDgQWBBRqgbARQ6Cx +o+9uCtUBhAAuSsUqsTAfBgNVHSMEGDAWgBQ2YeEAfIgFCVGLRGxH/xpMyepPEjAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDBQBgNVHR8ESTBHMEWgQ6BB +hj9odHRwczovL2FuZHJvaWQuZ29vZ2xlYXBpcy5jb20vYXR0ZXN0YXRpb24vY3Js +L0U4RkExOTYzMTREMkZBMTgwDQYJKoZIhvcNAQELBQADggIBAFPT8lzyoVECUHxp +mXWdOqC6eIgxELe9EkEEoZ+kyFGEWKYItJ3P1SHREBPmgXdP5zVYP6Ai0f1c88Hl +2DAnDZQ5VmnY08O/GxoP7t/t3Pa26TOnG1dxxNIU9iPwY+3Rry9GmwSRk5BC6PSa +XUZ1tsKSeJBNAONnAnaJin+9M0tK8wRRgyFFBVhZtgOLNPGUMDsNUAqpw/mH1JFb +AGZ6lIp1p6/t/+sVFmsAMS+X4ZDJ5Lv3wiK0wfsXhV9aq8G7GCMdebk66fsNLze8 +6kPb/kgwzQp+PyeOUmCJmPmNGtoZW9grx0P/kdSzNb7rX4fzzSNW2+J2EmWsj1qf +LPUc5BNsupBgcUq2v0pM6+/W81RyrNTnALSvU50rILjB5ov6wuGYxNxTNO5qkI/A +9exa+VFtijr98U6Qb6DczI5CU9dJbDO49JJBeXBKwFsxtnuow0jL8SC/KRUyECC1 +cjpO6FgkNuJUr5zuwOMbgi4hoCOZSOl6KfYeOokLVn38zEPzc3EXE3+BkZsSi0Mh +tcv30dcRR//2RdTZ67YDzHcPJbmqMDaUgDb18cKR1jI/9HYeYNJs8q2iiocDBwEH +prRK+LVRCvu/3sBoQOePJ6DRdoHkLyl3UCfJW6gpvWig/EUfLwo2HxDfB2mIoxfi +1DhCdEb6cfihod0NVm1TQzekh7s+ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICJTCCAaugAwIBAgIKFJFhkHRjCHkTEzAKBggqhkjOPQQDAjApMRkwFwYDVQQF +ExAxZGY0ZTA2YTZjNDJmNjUxMQwwCgYDVQQMDANURUUwHhcNMTkwNDE5MjA0MzM1 +WhcNMjkwNDE2MjA0MzM1WjApMRkwFwYDVQQFExA3YmIyODNhYzZhMTJlZjQyMQww +CgYDVQQMDANURUUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQg8ESy1cm/geei +pjZ0+ICsdGXWFhk39+NstMkef2yyv4WFdSS2aJsD2yYaCq2NbsrlwLkqeac5q9Do +7TMC9kCvo4G6MIG3MB0GA1UdDgQWBBTJnSBDgBTwTVVBhI0E6h4knugQ2zAfBgNV +HSMEGDAWgBRqgbARQ6Cxo+9uCtUBhAAuSsUqsTAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwICBDBUBgNVHR8ETTBLMEmgR6BFhkNodHRwczovL2FuZHJvaWQu +Z29vZ2xlYXBpcy5jb20vYXR0ZXN0YXRpb24vY3JsLzE0OTE2MTkwNzQ2MzA4Nzkx +MzEzMAoGCCqGSM49BAMCA2gAMGUCMQCZHAGiDQlu+OL5B/PmUFuV2A1yrWhsto7p +HIhWCre4X72R/WNczwmV0vScL4Bs0d4CMFBQoYOMOvKrcS6aIMRngdIb0dq6rnky +lQ3V6ltZhRrwjLhSJXRTmfmKVl1EetLnTw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDajCCAw+gAwIBAgIBATAKBggqhkjOPQQDAjApMRkwFwYDVQQFExA3YmIyODNh +YzZhMTJlZjQyMQwwCgYDVQQMDANURUUwIhgPMTkwMDAxMDAwMDAwMDBaGA8xOTAw +MDEwMDAwMDAwMFowHzEdMBsGA1UEAwwUQW5kcm9pZCBLZXlzdG9yZSBLZXkwWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAASbAjss6m590Hhe5f8qKF9uY1ZXM84TzsSQ +2MXzDzg2k4oGEbdIXeXSYlzRE2ef6ah/cSpVmMSdgGI6UtruotNNo4ICLDCCAigw +CwYDVR0PBAQDAgeAMIIB9gYKKwYBBAHWeQIBEQSCAeYwggHiAgECCgEBAgEDCgEB +BCC3eRgNT1K9PGox3+W1BcmuDrEXOsQ7e6YdHP3X3QhJIAQAMFC/hT0IAgYBiYZF ++QC/hUVABD4wPDEWMBQEDGNvbS53aGF0c2FwcAIEDcd7LTEiBCA5h9BD0Qrvr1qH +ELNnFBj+V+Dhm2U8nfglWP61/85dRDCCAVyhBTEDAgECogMCAQOjBAICAQClCDEG +AgEEAgEGqgMCAQG/g3cCBQC/hT4DAgEAv4VAggEWMIIBEgSCAQj///////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////8BAQEKAQC/hUEFAgMBOOS/hUIFAgMDFXcwHwYDVR0jBBgw +FoAUyZ0gQ4AU8E1VQYSNBOoeJJ7oENswCgYIKoZIzj0EAwIDSQAwRgIhAP3ncHkT +Ipyicm8CFF3cy45WpsV1o6IrAGsMQ3cioFXaAiEAtA3JDRfE9/CUUSCwaulH9u3O +FKDClEVeLWdhXE0HobU= +-----END CERTIFICATE----- \ No newline at end of file -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor