Skip to content

Conversation

@adrigonzo
Copy link

These four options to secure earlier TLS versions are actually unsupported by TLS1.3 and are sometimes added by default (e.g. in Plug and Plug Cowboy):

  • secure_renegotiate
  • reuse_sessions
  • next_protocols_advertised
  • alpn_preferred_protocols

When earlier versions aren't being enabled, this gives an error from OTP SSL module. Remove these options if TLS1.3 is the only enabled protocol, to get around this error.

@adrigonzo
Copy link
Author

Fixes also submitted for Plug and Plug Cowboy:
elixir-plug/plug#1011
elixir-plug/plug_cowboy#63

@essen
Copy link
Member

essen commented Feb 8, 2021

I don't know if this is something we want, but that's definitely not the right place, TLS related code should only be in ranch_ssl.

@adrigonzo
Copy link
Author

I don't know if this is something we want, but that's definitely not the right place, TLS related code should only be in ranch_ssl.

I'll take a look into moving it then. thank you.

@adrigonzo
Copy link
Author

I don't know if this is something we want, but that's definitely not the right place, TLS related code should only be in ranch_ssl.

I've moved it to ranch_ssl now. This may be redundant if the application using ranch doesn't force-add those options. It's where I made the change originally to get TLS1.3 working in a web application using Plug and Plug Cowboy over Ranch.

@michaelklishin
Copy link
Contributor

This is not pretty but I personally think it's the right thing to do. For example, we had to document these limitations for RabbitMQ but many users don't read any docs until things fail, often too late in the process (e.g. at deployment time).

Copy link
Contributor

@Maria-12648430 Maria-12648430 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments inline :)

ok.

-spec strip_usupported_options(opts()) -> opts().
strip_usupported_options(SocketOpts) ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo? usupported --> unsupported?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, thank you for spotting that. The downside of autocomplete once it was written wrong.


-spec strip_usupported_options(opts()) -> opts().
strip_usupported_options(SocketOpts) ->
case lists:keyfind(versions, 1, SocketOpts) of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is only part of it, ie the versions key in the socket options is not the only place influencing it. According to the ssl docs here, if absent it can also be set by an environment option for the ssl application, and if absent there it defaults to all versions that are supported (which can probably be found out by examining the supported key in the return from ssl:versions()).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if you mean that other options could give a value of 'tlsv1.3' for a version number, not only {versions, ['tlsv1.3']}; however, just to clarify, we found that as long as other options are specified in addition to 'tlsv1.3', .e.g. {versions, ['tlsv1.2', 'tlsv1.3']}, then the SSL error does not occur.

Copy link
Contributor

@juhlig juhlig Mar 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We mean that the versions could be implicitly ['tlsv1.3'] even if you don't specify them at all in the socket options, namely if they are specified in the ssl application environment. Like, try starting your node with erl -ssl protocol_versions "['tlsv1.3']". If you later give other versions in the socket options, that overrides those environment settings, but if you leave them out, the ssl application environment protocol_versions is taken for versions. If that is not defined either, versions default to all supported versions, which is probably more than only ['tlsv1.3'].
So, I guess what I mean is, if you don't find versions in the socket options, see if there is a protocol_versions key in the application environment of ssl, and if that is set to ['tlsv1.3].

_ ->
SocketOpts
end;
strip_usupported_options(SocketOpts) ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This clause is pointless, it will never be reached.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove this. It was inherited from the code, which I'd moved from the acceptors file.

Intermediate1 = lists:keydelete(secure_renegotiate, 1, SocketOpts),
Intermediate2 = lists:keydelete(reuse_sessions, 1, Intermediate1),
Intermediate3 = lists:keydelete(next_protocols_advertised, 1, Intermediate2),
lists:keydelete(alpn_preferred_protocols, 1, Intermediate3);
Copy link
Contributor

@Maria-12648430 Maria-12648430 Mar 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor detail probably, but this is not exhaustive either. lists:keydelete only removes the first occurrence, but in reality the same option may be given multiple times, pointless as that may be (if it follows the practice used in gen_tcp, not 100% sure for ssl). To be on the safe side, you'll have to lists:filter/2 the socket options.

@essen
Copy link
Member

essen commented Mar 9, 2021

Please do not silently drop the values, instead we should call logger:warning to inform the user that these settings were dropped.

/cc @lhoguin

@adrigonzo
Copy link
Author

adrigonzo commented Apr 14, 2021

I hope I resolved the above suggestions:

  • checking versions and protocol_versions for ['tlsv1.3'] option.
  • checking for the 4 listed options using lists:filter
  • added logger:warning to alert system of the changes

The only thing I wasn't quite sure of was, can protocol_versions be present with the ['tlsv1.3'] setting, while the user passes in a different versions option, which supersedes protocol_versions? If that were so, I think the clause of the if statement may need to be changed to:

    if
        (Versions1 == {versions, ['tlsv1.3']}) or ((Versions1 == false) and (Versions2 == {protocol_versions, ['tlsv1.3']})) ->

-spec strip_unsupported_options(opts()) -> opts().
strip_unsupported_options(SocketOpts) ->
Versions1 = lists:keyfind(versions, 1, SocketOpts),
Versions2 = lists:keyfind(protocol_versions, 1, SocketOpts),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protocol_versions is not in SocketOpts but in the environment of the ssl application

application:get_env(ssl, protocol_versions)

If versions is given in SocketOpts, it overrides protocol_versions from the application environment.

if
NewSocketOpts /= SocketOpts ->
error_logger:warning_msg("~p~n dropping options unsupported by TLS1.3-only ssl sockets: " ++
"secure_renegotiate, reuse_sessions, next_protocols_advertised and/or alpn_preferred_protocols from ~p~n", [?MODULE, SocketOpts])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should not use error_logger directly here (or logger, for that matter), but ranch:log/3 with the value from the logger key in TransOpts (as given to ranch_ssl: listen).

Also, the message is at the same time very verbose and doesn't tell very much, ie which options were actually dropped.

if
(Versions1 == {versions, ['tlsv1.3']}) or (Versions2 == {protocol_versions, ['tlsv1.3']}) ->
NewSocketOpts = lists:filter(fun({X, _}) ->
(X /= secure_renegotiate) and (X /= reuse_sessions) and (X /= next_protocols_advertised) and (X /= alpn_preferred_protocols);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to do it this way (and I'm pretty sure that @essen will object 😅), you should use andalso. But it may be better to have individual clauses for each, so you could log what you found and dropped along the way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to log what is dropped indeed.

@Maria-12648430
Copy link
Contributor

This PR seems to have dried up. I can take it on if you want?

@adrigonzo
Copy link
Author

This PR seems to have dried up. I can take it on if you want?

Hi, I believe you had a PR se-apc#3 for this. It's probably in more correct format as I'm not an Erlang programmer. It's ok if you want to go ahead and merge it in. The fix is working for us on a local branch, so I've not had to go back and touch it again (if it ain't broke, etc.... )
Thanks for checking in!

@essen
Copy link
Member

essen commented Aug 30, 2021

@Maria-12648430 Please take over the PR then. I think it would be good to release it in Ranch 2.1 along with the other ones.

@Maria-12648430
Copy link
Contributor

@Maria-12648430 Please take over the PR then. I think it would be good to release it in Ranch 2.1 along with the other ones.

@essen see #324

@essen
Copy link
Member

essen commented Aug 31, 2021

Closed in favor of #324.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants