Skip to content

Commit

Permalink
Merge branch 'maint'
Browse files Browse the repository at this point in the history
  • Loading branch information
IngelaAndin committed Nov 2, 2023
2 parents d4e9840 + 219f158 commit b4d0fc7
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 14 deletions.
20 changes: 20 additions & 0 deletions lib/public_key/src/pubkey_cert.erl
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,20 @@ 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],
#path_validation_state{last_cert = false} = ValidationState, 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'{} = Extension | Rest],
ValidationState, ExistBasicCon,
SelfSigned, UserState0, VerifyFun) ->
Expand Down Expand Up @@ -1502,3 +1516,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.
32 changes: 32 additions & 0 deletions lib/public_key/test/public_key_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -156,6 +158,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_dsa_sha2_oid,
Expand Down Expand Up @@ -934,6 +937,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:
%%
Expand Down
32 changes: 20 additions & 12 deletions lib/ssl/src/ssl_certificate.erl
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
file_to_certificats/2,
file_to_crls/2,
validate/3,
is_valid_extkey_usage/2,
is_valid_key_usage/2,
select_extension/2,
extensions_list/1,
Expand Down Expand Up @@ -207,27 +206,29 @@ file_to_crls(File, DbHandle) ->
%% Description: Validates ssl/tls specific extensions
%%--------------------------------------------------------------------
validate(_,{extension, #'Extension'{extnID = ?'id-ce-extKeyUsage',
extnValue = KeyUse}}, UserState = #{role := Role}) ->
case is_valid_extkey_usage(KeyUse, Role) of
critical = Critical,
extnValue = KeyUse}}, #{path_len := 1} = UserState) ->
%% If extension in peer, check for TLS server/client usage
case is_valid_extkey_usage(KeyUse, Critical, UserState) of
true ->
{valid, UserState};
false ->
{fail, {bad_cert, invalid_ext_key_usage}}
{unknown, UserState}
end;
validate(_, {extension, _}, UserState) ->
{unknown, UserState};
validate(Issuer, {bad_cert, cert_expired}, #{issuer := Issuer}) ->
{fail, {bad_cert, root_cert_expired}};
validate(_, {bad_cert, _} = Reason, _) ->
{fail, Reason};
validate(Cert, valid, UserState) ->
validate(Cert, valid, #{path_len := N} = UserState) ->
case verify_sign(Cert, UserState) of
true ->
case maps:get(cert_ext, UserState, undefined) of
undefined ->
{valid, UserState};
{valid, UserState#{path_len => N-1}};
_ ->
verify_cert_extensions(Cert, UserState)
verify_cert_extensions(Cert, UserState#{path_len => N-1})
end;
false ->
{fail, {bad_cert, invalid_signature}}
Expand Down Expand Up @@ -498,13 +499,20 @@ do_find_issuer(IssuerFun, CertDbHandle, CertDb) ->
throw:{ok, _} = Return ->
Return
end.

is_valid_extkey_usage(KeyUse, client) ->

is_valid_extkey_usage(KeyUse, true, #{role := Role}) when is_list(KeyUse) ->
is_valid_key_usage(KeyUse, ext_keysage(Role));
is_valid_extkey_usage(KeyUse, true, #{role := Role}) ->
is_valid_key_usage([KeyUse], ext_keysage(Role));
is_valid_extkey_usage(_, false, _) ->
false.

ext_keysage(client) ->
%% Client wants to verify server
is_valid_key_usage(KeyUse,?'id-kp-serverAuth');
is_valid_extkey_usage(KeyUse, server) ->
?'id-kp-serverAuth';
ext_keysage(server) ->
%% Server wants to verify client
is_valid_key_usage(KeyUse, ?'id-kp-clientAuth').
?'id-kp-clientAuth'.

verify_cert_signer(BinCert, SignerTBSCert) ->
PublicKey = public_key(SignerTBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo),
Expand Down
4 changes: 3 additions & 1 deletion lib/ssl/src/ssl_handshake.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3843,7 +3843,9 @@ path_validation(TrustedCert, Path, ServerName, Role, CertDbHandle, CertDbRef, CR
cert_ext => CertExt,
issuer => TrustedCert,
ocsp_responder_certs => OcspResponderCerts,
ocsp_state => OcspState},
ocsp_state => OcspState,
path_len => length(Path)
},
Path, Level),
Options = [{max_path_length, maps:get(depth, Opts, ?DEFAULT_DEPTH)},
{verify_fun, ValidationFunAndState}],
Expand Down
3 changes: 2 additions & 1 deletion lib/ssl/src/tls_handshake_1_3.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1881,7 +1881,8 @@ path_validation(TrustedCert, Path, ServerName, Role, CertDbHandle, CertDbRef, CR
issuer => TrustedCert,
cert_ext => CertExt,
ocsp_responder_certs => OcspResponderCerts,
ocsp_state => OcspState
ocsp_state => OcspState,
path_len => length(Path)
},
Path, LogLevel),
Options = [{max_path_length, maps:get(depth, Opts, ?DEFAULT_DEPTH)},
Expand Down

0 comments on commit b4d0fc7

Please sign in to comment.