Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:23
erlang
4542-ssl-Refactor-to-avoid-re-encoding-of-decod...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 4542-ssl-Refactor-to-avoid-re-encoding-of-decoded-certs.patch of Package erlang
From 58b7b1b37a349bf854ac1346201b49edacd2fc65 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin <ingela@erlang.org> Date: Tue, 21 Sep 2021 17:16:01 +0200 Subject: [PATCH 2/5] ssl: Refactor to avoid re-encoding of decoded certs Let public key define the record #cert{} that can be used to provide the original DER certs received from the peer and the decoded version together as input to certificate handling functions such as public:pkix_path_validation/3 will be more efficient as we can avoid conversions and also a way for applications such as ssl to tolerate certs with some ASN1-encoding errors that can be worked around. --- lib/public_key/doc/src/public_key.xml | 62 +++++++++++++++++---------- lib/public_key/include/public_key.hrl | 5 +++ lib/public_key/src/public_key.erl | 43 +++++++++++++------ lib/ssl/src/ssl_certificate.erl | 22 ++++------ lib/ssl/src/ssl_crl.erl | 2 +- lib/ssl/src/ssl_handshake.erl | 13 ++++-- lib/ssl/src/ssl_internal.hrl | 1 - 7 files changed, 94 insertions(+), 54 deletions(-) diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 4f569f2c6d..f4eb4bdefd 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -64,6 +64,14 @@ </desc> </datatype> + <datatype> + <name name="key_oid_name"/> + <desc> + <p>Macro names for key object identifiers used by prefixing with ?</p> + </desc> + </datatype> + + <datatype> <name name="der_encoded"/> <desc> @@ -100,11 +108,14 @@ <datatype> <name name="public_key"/> <name name="rsa_public_key"/> + <name name="dss_public_key"/> <name name="rsa_pss_public_key"/> <name name="dsa_public_key"/> <name name="ec_public_key"/> + <name name="public_key_params"/> <name name="ecpk_parameters"/> <name name="ecpk_parameters_api"/> + <name name="public_key_info"/> <desc> </desc> </datatype> @@ -139,6 +150,12 @@ </desc> </datatype> + <datatype> + <name name="ed_oid_name"/> + <desc> + Macro names for object identifiers for EDDSA curves used by prefixing with ? + </desc> + </datatype> <datatype> <name name="key_params"/> @@ -146,6 +163,7 @@ </desc> </datatype> + <datatype> <name name="digest_type"/> <desc> @@ -153,17 +171,32 @@ </datatype> <datatype> - <name name="crl_reason"/> + <name name="cert_id"/> <desc> </desc> </datatype> + <datatype> + <name name="cert"/> + <desc> + </desc> + </datatype> + + <datatype> - <name name="cert_id"/> + <name name="bad_cert_reason"/> <desc> </desc> </datatype> + + <datatype> + <name name="crl_reason"/> + <desc> + </desc> + </datatype> + + <datatype> <name name="issuer_name"/> <desc> @@ -401,33 +434,16 @@ </func> <func> - <name since="OTP R16B">pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, {PublicKeyInfo, PolicyTree}} | {error, {bad_cert, Reason}} </name> + <name since="OTP R16B" name="pkix_path_validation" arity="3"/> <fsummary>Performs a basic path validation according to RFC 5280.</fsummary> - <type> - <v>TrustedCert = #'OTPCertificate'{} | der_encoded() | atom()</v> - <d>Normally a trusted certificate, but it can also be a path-validation - error that can be discovered while - constructing the input to this function and that is to be run through the <c>verify_fun</c>. - Examples are <c>unknown_ca</c> and <c>selfsigned_peer.</c> - </d> - <v>CertChain = [der_encoded()]</v> - <d>A list of DER-encoded certificates in trust order ending with the peer certificate.</d> - <v>Options = proplists:proplist()</v> - <v>PublicKeyInfo = {?'rsaEncryption' | ?'id-RSASSA-PSS'| ?'id-dsa', - rsa_public_key() | integer(), 'NULL' | 'RSASSA-PSS-params'{} | 'Dss-Parms'{}}</v> - <v>PolicyTree = term()</v> - <d>At the moment this is always an empty list as policies are not currently supported.</d> - <v>Reason = cert_expired | invalid_issuer | invalid_signature | name_not_permitted | - missing_basic_constraint | invalid_key_usage | {revoked, crl_reason()} | atom() - </v> - </type> <desc> <p> Performs a basic path validation according to <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280.</url> However, CRL validation is done separately by <seemfa marker="#pkix_crls_validate/3">pkix_crls_validate/3 </seemfa> and is to be called - from the supplied <c>verify_fun</c>. + from the supplied <c>verify_fun</c>. The optional policy tree check is currently not implemented + but an empty place holder list is returned instead. </p> <p>Available options:</p> @@ -473,7 +489,7 @@ fun(OtpCert :: #'OTPCertificate'{}, </item> </taglist> - <p>Possible reasons for a bad certificate: </p> + <p>Explanations of reasons for a bad certificate: </p> <taglist> <tag>cert_expired</tag> <item><p>Certificate is no longer valid as its expiration date has passed.</p></item> diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl index 98d032bfdd..bea4b5bc06 100644 --- a/lib/public_key/include/public_key.hrl +++ b/lib/public_key/include/public_key.hrl @@ -78,6 +78,11 @@ point }). +-record(cert, { + der :: public_key:der_encoded(), + otp :: #'OTPCertificate'{} + }). + -define(unspecified, 0). -define(keyCompromise, 1). -define(cACompromise, 2). diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 6ecb902db5..0371917009 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -103,10 +103,12 @@ -type private_key() :: rsa_private_key() | rsa_pss_private_key() | dsa_private_key() | ec_private_key() | ed_private_key() . -type rsa_public_key() :: #'RSAPublicKey'{}. -type rsa_private_key() :: #'RSAPrivateKey'{}. --type rsa_pss_public_key() :: {#'RSAPublicKey'{}, #'RSASSA-PSS-params'{}}. +-type dss_public_key() :: integer(). +-type rsa_pss_public_key() :: {rsa_pss_public_key(), #'RSASSA-PSS-params'{}}. -type rsa_pss_private_key() :: { #'RSAPrivateKey'{}, #'RSASSA-PSS-params'{}}. -type dsa_private_key() :: #'DSAPrivateKey'{}. --type dsa_public_key() :: {integer(), #'Dss-Parms'{}}. +-type dsa_public_key() :: {dss_public_key(), #'Dss-Parms'{}}. +-type public_key_params() :: 'NULL' | #'RSASSA-PSS-params'{} | {namedCurve, oid()} | #'ECParameters'{} | #'Dss-Parms'{}. -type ecpk_parameters() :: {ecParameters, #'ECParameters'{}} | {namedCurve, Oid::tuple()}. -type ecpk_parameters_api() :: ecpk_parameters() | #'ECParameters'{} | {namedCurve, Name::crypto:ec_named_curve()}. -type ec_public_key() :: {#'ECPoint'{}, ecpk_parameters_api()}. @@ -114,7 +116,8 @@ -type ed_public_key() :: {#'ECPoint'{}, ed_params()} | {ed_pub, ed25519|ed448, Key::binary()}. -type ed_private_key() :: #'ECPrivateKey'{parameters :: ed_params()} | {ed_pri, ed25519|ed448, Pub::binary(), Priv::binary()}. --type ed_params() :: {namedCurve, ?'id-Ed25519' | ?'id-Ed448'}. +-type ed_oid_name() :: 'id-Ed25519' | 'id-Ed448'. +-type ed_params() :: {namedCurve, ed_oid_name()}. -type key_params() :: #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} | {rsa, Size::integer(), PubExp::integer()}. -type der_encoded() :: binary(). @@ -151,7 +154,11 @@ -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 | + {revoked, crl_reason()} | atom(). +-type cert() :: #cert{} | der_encoded() | #'OTPCertificate'{}. +-type public_key_info() :: {key_oid_name(), rsa_public_key() | #'ECPoint'{} | dss_public_key(), public_key_params()}. +-type key_oid_name() :: 'rsaEncryption' | 'id-RSASSA-PSS' | 'id-ecPublicKey' | 'id-Ed25519' | 'id-Ed448' | 'id-dsa'. -define(UINT32(X), X:32/unsigned-big-integer). @@ -1095,16 +1102,22 @@ pkix_normalize_name(Issuer) -> pubkey_cert:normalize_general_name(Issuer). %%-------------------------------------------------------------------- --spec pkix_path_validation(Cert::binary()| #'OTPCertificate'{} | atom(), - CertChain :: [binary() | #'OTPCertificate'{}] , - Options :: [{atom(),term()}]) -> - {ok, {PublicKeyInfo :: term(), - PolicyTree :: term()}} | - {error, {bad_cert, Reason :: term()}}. +-spec pkix_path_validation(Cert, CertChain, Options) -> + {ok, {PublicKeyInfo, PolicyTree}} | + {error, {bad_cert, Reason :: bad_cert_reason()}} + when + Cert::binary()| #'OTPCertificate'{} | atom(), + CertChain :: [cert()], + Options :: [Option], + Option :: {verify_fun, {fun(), term()}} | {max_path_lengh, integer()}, + PublicKeyInfo :: public_key_info(), + PolicyTree :: list(). + %% Description: Performs a basic path validation according to RFC 5280. %%-------------------------------------------------------------------- pkix_path_validation(TrustedCert, CertChain, Options) when is_binary(TrustedCert) -> + OtpCert = pkix_decode_cert(TrustedCert, otp), pkix_path_validation(OtpCert, CertChain, Options); pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options) @@ -1641,13 +1654,17 @@ validate(Cert, #path_validation_state{working_issuer_name = Issuer, otp_cert(Der) when is_binary(Der) -> pkix_decode_cert(Der, otp); -otp_cert(#'OTPCertificate'{} =Cert) -> - Cert. +otp_cert(#'OTPCertificate'{} = Cert) -> + Cert; +otp_cert(#cert{otp = OtpCert}) -> + OtpCert. der_cert(#'OTPCertificate'{} = Cert) -> pkix_encode('OTPCertificate', Cert, otp); der_cert(Der) when is_binary(Der) -> - Der. + Der; +der_cert(#cert{der = DerCert}) -> + DerCert. pkix_crls_validate(_, [],_, Options, #revoke_state{details = Details}) -> case proplists:get_value(undetermined_details, Options, false) of diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index cbeb4e4521..acdc85255f 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -88,7 +88,7 @@ %%-------------------------------------------------------------------- -spec trusted_cert_and_paths([der_cert()], db_handle(), certdb_ref(), fun()) -> - [{der_cert() | unknown_ca | invalid_issuer | selfsigned_peer, [der_cert()]}]. + [{#cert{} | unknown_ca | invalid_issuer | selfsigned_peer, [#cert{}]}]. %% %% Description: Construct input to public_key:pkix_path_validation/3, %% If the ROOT cert is not found {bad_cert, unknown_ca} will be returned @@ -103,7 +103,7 @@ trusted_cert_and_paths([Peer], CertDbHandle, CertDbRef, PartialChainHandler) -> Chain = [#cert{der=Peer, otp=OtpCert}], case public_key:pkix_is_self_signed(OtpCert) of true -> - [{selfsigned_peer, [Peer]}]; + [{selfsigned_peer, Chain}]; false -> [handle_incomplete_chain(Chain, PartialChainHandler, {unknown_ca, Chain}, CertDbHandle, CertDbRef)] @@ -122,11 +122,10 @@ trusted_cert_and_paths(Chain0, CertDbHandle, CertDbRef, PartialChainHandler) -> PartialChainHandler, Result, CertDbHandle, CertDbRef); - {Root, NewChain}-> - decoded_chain(Root, NewChain) + {_Root, _NewChain} = Result -> + Result end end, Paths). - %%-------------------------------------------------------------------- -spec certificate_chain(undefined | binary() | #'OTPCertificate'{} , db_handle(), certdb_ref() | {extracted, list()}) -> @@ -362,9 +361,8 @@ do_certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _, ListD {ok, undefined, lists:reverse(Chain)} end. -find_alternative_root([OtpCert | _], CertDbHandle, CertDbRef, InvalidatedList) -> - Cert = public_key:pkix_encode('OTPCertificate', OtpCert, otp), - case find_issuer(#cert{der=Cert, otp=OtpCert}, CertDbHandle, CertDbRef, [], InvalidatedList) of +find_alternative_root([Cert | _], CertDbHandle, CertDbRef, InvalidatedList) -> + case find_issuer(Cert, CertDbHandle, CertDbRef, [], InvalidatedList) of {error, issuer_not_found} -> unknown_ca; {ok, {SerialNr, IssuerId}} -> @@ -663,14 +661,12 @@ handle_incomplete_chain([#cert{}=Peer| _] = Chain0, PartialChainHandler, Default true -> {Root, Chain} = handle_partial_chain(lists:reverse(ChainCandidate), PartialChainHandler, CertDbHandle, CertDbRef), - decoded_chain(Root, Chain); + {Root, Chain}; false -> - {Root, Chain} = Default, - decoded_chain(Root, Chain) + Default end; _ -> - {Root, Chain} = Default, - decoded_chain(Root, Chain) + Default end. extraneous_chains(Certs) -> diff --git a/lib/ssl/src/ssl_crl.erl b/lib/ssl/src/ssl_crl.erl index 5e35e89b78..d3b66df870 100644 --- a/lib/ssl/src/ssl_crl.erl +++ b/lib/ssl/src/ssl_crl.erl @@ -105,7 +105,7 @@ find_issuer(IsIssuerFun, Db, _) -> Result end. -verify_crl_issuer(CRL, ErlCertCandidate, Issuer, NotIssuer) -> +verify_crl_issuer(CRL, #cert{otp = ErlCertCandidate}, Issuer, NotIssuer) -> TBSCert = ErlCertCandidate#'OTPCertificate'.tbsCertificate, case public_key:pkix_normalize_name(TBSCert#'OTPTBSCertificate'.subject) of Issuer -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index f7dc641fb3..63fbf5ffff 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -3726,9 +3726,9 @@ path_validate([], _, _, _, _, _, _, _, _, _, Error) -> path_validate([{TrustedCert, Path} | Rest], ServerName, Role, CertDbHandle, CertDbRef, CRLDbHandle, Version, SslOptions, CertExt, InvalidatedList, Error) -> CB = path_validation_cb(Version), - case CB:path_validation(TrustedCert, Path, ServerName, - Role, CertDbHandle, CertDbRef, CRLDbHandle, - Version, SslOptions, CertExt) of + case CB:path_validation(trusted_unwrap(TrustedCert), Path, ServerName, + Role, CertDbHandle, CertDbRef, CRLDbHandle, + Version, SslOptions, CertExt) of {error, {bad_cert, root_cert_expired}} = NewError -> NewInvalidatedList = [TrustedCert | InvalidatedList], Alt = ssl_certificate:find_cross_sign_root_paths(Path, CertDbHandle, CertDbRef, NewInvalidatedList), @@ -3745,6 +3745,13 @@ path_validate([{TrustedCert, Path} | Rest], ServerName, Role, CertDbHandle, Cert Result end. +trusted_unwrap(#cert{otp = TrustedCert}) -> + TrustedCert; +trusted_unwrap(#'OTPCertificate'{} = TrustedCert) -> + TrustedCert; +trusted_unwrap(ErrAtom) when is_atom(ErrAtom) -> + ErrAtom. + %% Call basic path validation algorithm in public_key pre TLS-1.3 path_validation(TrustedCert, Path, ServerName, Role, CertDbHandle, CertDbRef, CRLDbHandle, Version, #{verify_fun := VerifyFun, diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 3a8568d1e3..b56ba24d78 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -252,7 +252,6 @@ max_size %% max early data size allowed by this ticket }). --record(cert, {der, otp}). -endif. % -ifdef(ssl_internal). -- 2.31.1
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