File 3851-ssl-VerifyFun-can-now-get-the-der-cert-as-argument.patch of Package erlang
From 9d11335efa6c2b83ec48e26c85d6ac2e46e2bc9f Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson <dgud@erlang.org>
Date: Tue, 1 Nov 2022 17:01:54 +0100
Subject: [PATCH] ssl: VerifyFun can now get the der cert as argument
In some cases the user may want the original der cert as input to the
verify fun.
Allow the user to supply VerifyFun/4 as verify_fun option.
In later releases one can think that this should be enabled in
public_key functions as well.
---
lib/ssl/doc/src/ssl.xml | 21 ++++++++++++++++-----
lib/ssl/src/ssl_handshake.erl | 18 +++++++++++++-----
lib/ssl/test/ssl_cert_SUITE.erl | 24 ++++++++++++++++--------
3 files changed, 45 insertions(+), 18 deletions(-)
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 8c63b1d698..cf62d0979d 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -577,11 +577,22 @@ version.
<p>The verification fun is to be defined as follows:</p>
<code>
-fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() |
- {revoked, atom()}} |
- {extension, #'Extension'{}} | valid | valid_peer, InitialUserState :: term()) ->
+fun(OtpCert :: #'OTPCertificate'{},
+ Event, InitialUserState :: term()) ->
{valid, UserState :: term()} |
{fail, Reason :: term()} | {unknown, UserState :: term()}.
+
+fun(OtpCert :: #'OTPCertificate'{}, DerCert :: public_key:der_encoded(),
+ Event, InitialUserState :: term()) ->
+ {valid, UserState :: term()} |
+ {fail, Reason :: term()} | {unknown, UserState :: term()}.
+
+Types:
+ Event = {bad_cert, Reason :: atom() |
+ {revoked, atom()}} |
+ {extension, #'Extension'{}} |
+ valid |
+ valid_peer
</code>
<p>The verification fun is called during the X509-path
@@ -591,8 +602,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() |
allow access to each certificate in the path to the user
application. It differentiates between the peer certificate
and the CA certificates by using <c>valid_peer</c> or
- <c>valid</c> as second argument to the verification fun. See
- the <seeguide marker="public_key:public_key_records">public_key
+ <c>valid</c> as <c>Event</c> argument to the verification fun.
+ See the <seeguide marker="public_key:public_key_records">public_key
User's Guide</seeguide> for definition of
<c>#'OTPCertificate'{}</c> and <c>#'Extension'{}</c>.</p>
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index ee102077af..4e4f243c71 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -2020,8 +2020,8 @@ validation_fun_and_state(undefined, VerifyState, CertPath, LogLevel) ->
apply_user_fun(Fun, OtpCert, VerifyResult0, UserState0, SslState, CertPath, LogLevel) when
(VerifyResult0 == valid) or (VerifyResult0 == valid_peer) ->
VerifyResult = maybe_check_hostname(OtpCert, VerifyResult0, SslState),
- case Fun(OtpCert, VerifyResult, UserState0) of
- {Valid, UserState} when (Valid == valid) or (Valid == valid_peer) ->
+ case apply_fun(Fun, OtpCert, VerifyResult, UserState0, CertPath) of
+ {Valid, UserState} when (Valid == valid) orelse (Valid == valid_peer) ->
case cert_status_check(OtpCert, SslState, VerifyResult, CertPath, LogLevel) of
valid ->
{Valid, {SslState, UserState}};
@@ -2031,9 +2031,9 @@ apply_user_fun(Fun, OtpCert, VerifyResult0, UserState0, SslState, CertPath, LogL
{fail, _} = Fail ->
Fail
end;
-apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState, _CertPath, _LogLevel) ->
- case Fun(OtpCert, ExtensionOrError, UserState0) of
- {Valid, UserState} when (Valid == valid) or (Valid == valid_peer)->
+apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState, CertPath, _LogLevel) ->
+ case apply_fun(Fun, OtpCert, ExtensionOrError, UserState0, CertPath) of
+ {Valid, UserState} when (Valid == valid) orelse (Valid == valid_peer)->
{Valid, {SslState, UserState}};
{fail, _} = Fail ->
Fail;
@@ -2041,6 +2041,14 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState, _CertPath,
{unknown, {SslState, UserState}}
end.
+apply_fun(Fun, OtpCert, ExtensionOrError, UserState, CertPath) ->
+ if is_function(Fun, 4) ->
+ #cert{der=DerCert} = lists:keyfind(OtpCert, #cert.otp, CertPath),
+ Fun(OtpCert, DerCert, ExtensionOrError, UserState);
+ is_function(Fun, 3) ->
+ Fun(OtpCert, ExtensionOrError, UserState)
+ end.
+
maybe_check_hostname(OtpCert, valid_peer, SslState) ->
case ssl_certificate:validate(OtpCert, valid_peer, SslState) of
{valid, _} ->
diff --git a/lib/ssl/test/ssl_cert_SUITE.erl b/lib/ssl/test/ssl_cert_SUITE.erl
index 6b0b6f5f4d..e006146c9a 100644
--- a/lib/ssl/test/ssl_cert_SUITE.erl
+++ b/lib/ssl/test/ssl_cert_SUITE.erl
@@ -614,13 +614,17 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
%% If user verify fun is called correctly we fail the connection.
%% otherwise we cannot tell this case apart form where we miss
%% to call users verify fun
- FunAndState = {fun(_,{extension, _}, UserState) ->
+ FunAndState = {fun(_, Der, {extension, _}, UserState) ->
+ true = is_binary(Der),
{unknown, UserState};
- (_, valid, [ChainLen]) ->
+ (_, Der, valid, [ChainLen]) ->
+ true = is_binary(Der),
{valid, [ChainLen + 1]};
- (_, valid_peer, [1]) ->
+ (_, Der, valid_peer, [1]) ->
+ true = is_binary(Der),
{fail, "verify_fun_was_always_run"};
- (_, valid_peer, UserState) ->
+ (_, Der, valid_peer, UserState) ->
+ true = is_binary(Der),
{valid, UserState}
end, [0]},
@@ -648,13 +652,17 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
%% If user verify fun is called correctly we fail the connection.
%% otherwise we cannot tell this case apart form where we miss
%% to call users verify fun
- FunAndState = {fun(_,{extension, _}, UserState) ->
+ FunAndState = {fun(_, Der, {extension, _}, UserState) ->
+ true = is_binary(Der),
{unknown, UserState};
- (_, valid, [ChainLen]) ->
+ (_, Der, valid, [ChainLen]) ->
+ true = is_binary(Der),
{valid, [ChainLen + 1]};
- (_, valid_peer, [1]) ->
+ (_, Der, valid_peer, [1]) ->
+ true = is_binary(Der),
{fail, "verify_fun_was_always_run"};
- (_, valid_peer, UserState) ->
+ (_, Der, valid_peer, UserState) ->
+ true = is_binary(Der),
{valid, UserState}
end, [0]},
--
2.35.3