fix(ocsp): allow disabling ocsp without touching url

This commit is contained in:
Thales Macedo Garitezi 2022-11-07 17:50:02 -03:00
parent 26d2ed3d31
commit 11175b55f8
4 changed files with 46 additions and 12 deletions

View File

@ -1521,6 +1521,12 @@ listener.ssl.external.certfile = {{ platform_etc_dir }}/certs/cert.pem
## Value: File
listener.ssl.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem
## Wheter to enable OCSP for the listener.
##
## Value: boolean
## Default: false
## listener.ssl.external.enable_ocsp = true
## URL for the OCSP responder to check the server certificate against.
##
## Value: String

View File

@ -1679,6 +1679,11 @@ end}.
{datatype, {duration, ms}}
]}.
{mapping, "listener.ssl.$name.enable_ocsp", "emqx.listeners", [
{default, false},
{datatype, {enum, [true, false]}}
]}.
{mapping, "listener.ssl.$name.ocsp_responder_url", "emqx.listeners", [
{datatype, string}
]}.
@ -2237,6 +2242,7 @@ end}.
{supported_subprotocols, string:tokens(cuttlefish:conf_get(Prefix ++ ".supported_subprotocols", Conf, ""), ", ")},
{peer_cert_as_username, cuttlefish:conf_get(Prefix ++ ".peer_cert_as_username", Conf, undefined)},
{peer_cert_as_clientid, cuttlefish:conf_get(Prefix ++ ".peer_cert_as_clientid", Conf, undefined)},
{ocsp_enabled, cuttlefish:conf_get(Prefix ++ ".enable_ocsp", Conf, undefined)},
{ocsp_responder_url, cuttlefish:conf_get(Prefix ++ ".ocsp_responder_url", Conf, undefined)},
{ocsp_issuer_pem, cuttlefish:conf_get(Prefix ++ ".ocsp_issuer_pem", Conf, undefined)},
{ocsp_refresh_interval, cuttlefish:conf_get(Prefix ++ ".ocsp_refresh_interval", Conf, undefined)},

View File

@ -48,6 +48,11 @@
-define(CALL_TIMEOUT, 20_000).
-define(RETRY_TIMEOUT, 5_000).
-define(REFRESH_TIMER(LID), {refresh_timer, LID}).
-ifdef(TEST).
-define(MIN_REFRESH_INTERVAL, timer:seconds(5)).
-else.
-define(MIN_REFRESH_INTERVAL, timer:minutes(1)).
-endif.
%%--------------------------------------------------------------------
%% API
@ -93,10 +98,10 @@ inject_sni_fun(Listener = #{proto := Proto, name := Name, opts := Options0}) ->
%% because otherwise an anonymous function will end up in
%% `app.*.config'...
ListenerID = emqx_listeners:identifier(Listener),
case proplists:get_value(ocsp_responder_url, Options0, undefined) of
undefined ->
case proplists:get_bool(ocsp_enabled, Options0) of
false ->
Options0;
_URL ->
true ->
SSLOpts0 = proplists:get_value(ssl_options, Options0, []),
SNIFun = fun(SN) -> emqx_ocsp_cache:sni_fun(SN, ListenerID) end,
Options1 = proplists:delete(ssl_options, Options0),
@ -142,8 +147,7 @@ handle_call({register_listener, ListenerID}, _From, State0) ->
?LOG(debug, "registering ocsp cache for ~p", [ListenerID]),
#{opts := Opts} = emqx_listeners:find_by_id(ListenerID),
RefreshInterval0 = proplists:get_value(ocsp_refresh_interval, Opts),
MinimumRefrshInterval = timer:minutes(1),
RefreshInterval = max(RefreshInterval0, MinimumRefrshInterval),
RefreshInterval = max(RefreshInterval0, ?MIN_REFRESH_INTERVAL),
State = State0#{{refresh_interval, ListenerID} => RefreshInterval},
{reply, ok, ensure_timer(ListenerID, State, 0)};
handle_call(Call, _From, State) ->
@ -177,7 +181,8 @@ code_change(_Vsn, State, _Extra) ->
ListenersToPatch =
lists:filter(
fun(#{opts := Opts}) ->
undefined =/= proplists:get_value(ocsp_responder_url, Opts)
undefined =/= proplists:get_value(ocsp_responder_url, Opts) andalso
false =/= proplists:get_bool(ocsp_enabled, Opts)
end,
emqx:get_env(listeners, [])),
PatchedListeners = [L#{opts => ?MODULE:inject_sni_fun(L)} || L <- ListenersToPatch],

View File

@ -96,10 +96,10 @@ init_per_testcase(t_openssl_client, Config) ->
, {cacertfile, CACert}
]),
Opts1 = proplists:delete(ssl_options, Opts0),
Opts2 = [ {ocsp_responder_url, "http://127.0.0.1:9877"}
, {ocsp_issuer_pem, IssuerPem}
, {ssl_options, SSLOpts2}
| Opts1],
Opts2 = emqx_misc:merge_opts(Opts1, [ {ocsp_enabled, true}
, {ocsp_responder_url, "http://127.0.0.1:9877"}
, {ocsp_issuer_pem, IssuerPem}
, {ssl_options, SSLOpts2}]),
Listeners = [ SSLListener0#{opts => Opts2}
| Listeners1],
application:set_env(emqx, listeners, Listeners),
@ -109,7 +109,18 @@ init_per_testcase(t_openssl_client, Config) ->
end,
OCSPResponderPort = spawn_openssl_ocsp_responder(Config),
{os_pid, OCSPOSPid} = erlang:port_info(OCSPResponderPort, os_pid),
ensure_port_open(9877),
%%%%%%%% Warning!!!
%% Apparently, openssl 3.0.7 introduced a bug in the responder
%% that makes it hang forever if one probes the port with
%% `gen_tcp:open' / `gen_tcp:close'... Comment this out if
%% openssl gets updated in CI or in your local machine.
case openssl_version() of
"3." ++ _ ->
%% hope that the responder has started...
ok;
_ ->
ensure_port_open(9877)
end,
ct:sleep(1_000),
emqx_ct_helpers:start_apps([], Handler),
ct:sleep(1_000),
@ -134,6 +145,7 @@ init_per_testcase(_TestCase, Config) ->
, name => "test_ocsp"
, opts => [ {ssl_options, [{certfile,
filename:join(DataDir, "server.pem")}]}
, {ocsp_enabled, true}
, {ocsp_responder_url, "http://localhost:9877"}
, {ocsp_issuer_pem,
filename:join(DataDir, "ocsp-issuer.pem")}
@ -291,6 +303,11 @@ get_sni_fun(ListenerID) ->
SSLOpts = proplists:get_value(ssl_options, Opts),
proplists:get_value(sni_fun, SSLOpts).
openssl_version() ->
"OpenSSL " ++ Res = os:cmd("openssl version"),
{match, [Version]} = re:run(Res, "^([^ ]+)", [{capture, first, list}]),
Version.
%%--------------------------------------------------------------------
%% Test cases
%%--------------------------------------------------------------------
@ -417,7 +434,7 @@ t_refresh_periodically(_Config) ->
false
end,
_NEvents = 2,
_Timeout = 5_000),
_Timeout = 10_000),
ok = emqx_ocsp_cache:register_listener(ListenerID),
?assertMatch({ok, [_, _]}, snabbkaffe:receive_events(SubRef)),
assert_http_get(2),