otp icon indicating copy to clipboard operation
otp copied to clipboard

Simplified SSL option value for `cacerts`?

Open zmstone opened this issue 1 year ago • 7 comments

When one wants to use system default trusted certs to verify peer. There seems to be only two options:

  1. Extract the trusted CA certificates in a file, and provide cacertfile option
  2. Trust ALL default ca certs from the OS: {cacerts, public_key:cacerts_get()}

I'd like to have option 2 simplified as {cacerts, system_defaults} or similar so OTP's ssl lib can call public_key:cacerts_get() for me.

This is necessary because public_key:cacerts_get() is often a quite bloated term. And SSL options are usually passed around and stored in various process states. When process crashes or when exceptions with SSL options in the context are caught and dumped to logs, the options are printed to the logs which in turn bloats the logs quite much.

zmstone avatar Jun 19 '24 20:06 zmstone

A further enhancement is probably not to turn system_defaults into public_key:cacerts_get(), but use it as an indication to search for certs in certificate store which is periodically refreshed thus to ensure certificate renewal is smooth.

zmstone avatar Jun 22 '24 09:06 zmstone

Thank you for you input. We definitely will consider doing changes in this direction. We also have our own thoughts of a "caching mechanism" for cert provided as DER directly. Can not give you any estimates of when it can be prioritized.

IngelaAndin avatar Aug 27 '24 13:08 IngelaAndin

@IngelaAndin thank you. If the "caching mechanism" means passing a reference but not a large term, that's great. I am unsure why it's limited to DER format, but it could be a good start. Thanks.

Another point I added was the support for root CA certificates renewal (without having to restart). The current cacertfile solution has support for it (ssl lib periodically reloads it), but public_key:cacerts_get() is a immutable term. If the OS trusted certifcates can be loaded into a "cache", and then application can use a reference for it, I would wish this cache to be periodically refreshed.

zmstone avatar Aug 29 '24 20:08 zmstone

The result of public_key:cacerts_get() is stored on the literal area so it never is a bloated term, until it is printed that is. But until then it doesn't cost any memory and is already cached between users.

dgud avatar Aug 30 '24 06:08 dgud

Well I guess we have three things, if certs are provided as DER in options we want to create a cache. In public_key:get_cacerts case we want the cache to be refreshable as the PEM cache is. We also want https://github.com/erlang/otp/pull/8741 so that public_key:get_cacerts will not be printed by SASL progress reports.

IngelaAndin avatar Aug 30 '24 08:08 IngelaAndin

@zmstone As I said #8741 should fix you log problem, cacerts are not not printed in error reports already today so it is just the progress reports. For certs provided by cacerts that is not public_key:cacerts_get() but raw DER is the caching improvement I was thinking about. For PEM-files we have a really not disruptive cache refresh mechanism, but for system defaults as @dgud mentions is implemented differently. And maybe we need to think about if this should be handled by user application by calling public_key:cacerts_clear/0 instead? I am not sure about the tradeoffs here!?

IngelaAndin avatar Aug 30 '24 15:08 IngelaAndin

It's often more than SASL progress which may print the certs. When a config is constructed at application level, and passed down the abstraction layers, each layer may have its own idea about error handling and logging.

zmstone avatar Sep 07 '24 18:09 zmstone

If one uses a third party HTTP client (e.g. Hackney) this problem is not solved by #8741. For example, when Hackney is used in combination with tls_certificate_check and progress reporting is enabled in Logger, the following get printed into Common Test logs:

*** System report during my_test_SUITE:init_per_suite/1 2025-01-15 09:14:28.079 ***[🔗](file:///path/to/project/_build/test/logs/[email protected]_09.12.47/lib.my_app.logs/run.2025-01-15_09.12.48/my_test_suite.init_per_suite.html#e-5389)
=PROGRESS REPORT==== 15-Jan-2025::09:14:28.034467 ===
    supervisor: {local,hackney_sup}
    started: [{pid,<0.15886.0>},
              {id,<<"localhost">>},
              {mfargs,
                  {hackney_pool,start_link,
                      [<<"localhost">>,
                       [{name,<<"localhost">>},
                        with_body,
                        {pool,<<"localhost">>},
                        {ssl_options,
                            [{verify,verify_peer},
                             {depth,100},
                             {cacerts,
                                 [<<48,130,5,52,48,130,3,30,160,3,2,1,2,2,1,1,
                                    48,11,6,9,42,134,72,134,247,13,1,1,11,48,
                                    45,49,11,48,9,6,3,85,4,6,19,2,83,69,49,17,
                                    48,15,6,3,85,4,10,19,8,75,105,118,114,97,
                                    ...

Which is then followed by ~4 Mb of "pretty printed" certificate binaries.

It would be nice if it would be possible to pass in a persistent term of that certificate list or something smaller, that represents the full list. Something like {cacerts, {persistent_term, my_certs}} that would then make the SSL library read that persistent term.

eproxus avatar Jan 15 '25 13:01 eproxus