Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to request TLS client-side enforcement #525

Merged
merged 4 commits into from
Apr 20, 2022
Merged

Allow users to request TLS client-side enforcement #525

merged 4 commits into from
Apr 20, 2022

Conversation

FalacerSelene
Copy link
Contributor

This change allows users of the driver to request that the TLS version is at least a specified minimum. This helps to avoid downgrade attacks, such as POODLE.

In practice I'll always be wanting to call this to enforce TLS1.2, but I thought it made sense to make it optional, and to allow users to say which TLS version they care about so that the driver remains fully back-compatible and flexible.

Copy link
Contributor

@mpenick mpenick left a comment

Choose a reason for hiding this comment

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

Thanks for the feature. This is great. Looks good to me.

It might be nice to add a unit test here, but definitely not a deal breaker. I think we could probably add a socket test (around here): https://github.com/datastax/cpp-driver/blob/master/tests/src/unit/tests/test_socket.cpp#L255-L269. Something like set the version on the server to something too low and check for an error, etc.

@mpenick
Copy link
Contributor

mpenick commented Mar 24, 2022

This might be failing because of formatting. Try running make format (you'll need clang format installed locally).

Test covers trying to connect to a server that only supports TLS 1.0-,
while trying to enforce TLS 1.2+ on client-side. As expected, the
connection does not succeed.
@FalacerSelene
Copy link
Contributor Author

Great - thanks! Unit test added, and appveyor passed with it. I don't have visibility into why the jenkins run failed. I've run make format, which didn't recommend any changes.

@absurdfarce
Copy link
Collaborator

Most of the test failures look to be the following:

[2022-03-25T10:29:56.012Z] /home/jenkins/workspace/drivers_cpp_oss_PR-525/tests/src/unit/tests/test_socket.cpp:431: Failure
[2022-03-25T10:29:56.012Z] Value of: is_closed
[2022-03-25T10:29:56.012Z]   Actual: false
[2022-03-25T10:29:56.012Z] Expected: true
[2022-03-25T10:29:56.012Z] [  FAILED  ] SocketUnitTest.SslEnforceTlsVersion (124 ms)

That test did pass on one platform but failed on several others. That appears to be the main reason for the build failures.

@absurdfarce
Copy link
Collaborator

The other build issue looks to just be a formatting problem:

[2022-03-25T02:22:58.746Z] [  4%] Building CXX object src/CMakeFiles/cassandra.dir/address.cpp.o
[2022-03-25T02:22:58.746Z] cc1plus: warnings being treated as errors
[2022-03-25T02:22:58.746Z] In file included from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/memory.hpp:20,
[2022-03-25T02:22:58.746Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/allocated.cpp:18:
[2022-03-25T02:22:58.746Z] /home/jenkins/workspace/drivers_cpp_oss_PR-525/include/cassandra.h:635: error: comma at end of enumerator list
[2022-03-25T02:22:58.746Z] make[2]: *** [src/CMakeFiles/cassandra.dir/allocated.cpp.o] Error 1
[2022-03-25T02:22:58.746Z] make[2]: *** Waiting for unfinished jobs....
[2022-03-25T02:22:59.202Z] cc1plus: warnings being treated as errors
[2022-03-25T02:22:59.211Z] In file included from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/memory.hpp:20,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/ref_counted.hpp:23,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/callback.hpp:22,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/address.hpp:21,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/address.cpp:17:
[2022-03-25T02:22:59.211Z] /home/jenkins/workspace/drivers_cpp_oss_PR-525/include/cassandra.h:635: error: comma at end of enumerator list
[2022-03-25T02:22:59.211Z] cc1plus: warnings being treated as errors
[2022-03-25T02:22:59.211Z] In file included from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/memory.hpp:20,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/ref_counted.hpp:23,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/buffer.hpp:20,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/abstract_data.hpp:21,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/abstract_data.cpp:17:
[2022-03-25T02:22:59.211Z] /home/jenkins/workspace/drivers_cpp_oss_PR-525/include/cassandra.h:635: error: comma at end of enumerator list
[2022-03-25T02:22:59.211Z] cc1plus: warnings being treated as errors
[2022-03-25T02:22:59.211Z] In file included from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/memory.hpp:20,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/ref_counted.hpp:23,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/buffer.hpp:20,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/auth.hpp:20,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/config.hpp:20,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/address_factory.hpp:20,
[2022-03-25T02:22:59.211Z]                  from /home/jenkins/workspace/drivers_cpp_oss_PR-525/src/address_factory.cpp:17:
[2022-03-25T02:22:59.211Z] /home/jenkins/workspace/drivers_cpp_oss_PR-525/include/cassandra.h:635: error: comma at end of enumerator list

That failed on only one of the platform tests

@FalacerSelene
Copy link
Contributor Author

I've corrected the formatting error you pointed out - how do you suggest I proceed with the other fixes? It's going to be difficult for me to conclusively fix test failures that don't occur on my system and also don't occur somewhere I have access to.

@absurdfarce
Copy link
Collaborator

@FalacerSelene I agree it's hard for you to resolve build issues without additional information. The build failed due to what appears to be a formatting error on CentOS 6 and what looks to be the same test failure on most (but not all) of the other test platforms. I'll try to do some additional digging, see if I can provide more context on these failures.

@FalacerSelene
Copy link
Contributor Author

@FalacerSelene I agree it's hard for you to resolve build issues without additional information. The build failed due to what appears to be a formatting error on CentOS 6 and what looks to be the same test failure on most (but not all) of the other test platforms. I'll try to do some additional digging, see if I can provide more context on these failures.

If you could provide (or link to, if they're just public ones) docker images that replicate the failing environment(s) I could run tests in there to check.

@absurdfarce
Copy link
Collaborator

Unfortunately I can't easily share the images used to run the various test suites @FalacerSelene but I believe I can provide some additional context.

The errors reported by the Jenkins process are as follows:

  • Centos6 reports another formatting error of some kind
  • Centos7, Centos8, Ubuntu Bionic (18.x) and Ubuntu Trusty (14.x) report the following failure:
[ RUN      ] SocketUnitTest.SslEnforceTlsVersion
...
Value of: is_closed
  Actual: false
Expected: true
[  FAILED  ] SocketUnitTest.SslEnforceTlsVersion (20 ms)

Let's ignore the Centos6 issue for now and just focus on the test failure.

I initially thought this might be an issue with the handling of pre-TLS1.2 OpenSSL libs, but the fail/pass/fail sequence we see with Trusty/Xenial/Bionic on Ubuntu makes that seem far less likely. Fortunately I can reproduce this on a FedoraCore 28 environment. Based on testing there I can confirm that this isn't some kind of intermittent or timing issue; the test fails reliably on multiple runs.

The on_socket_closed function used in the callback is pretty straightforward:

  static void on_socket_closed(SocketConnector* connector, bool* is_closed) {
    if (connector->error_code() == SocketConnector::SOCKET_ERROR_CLOSE) {
      *is_closed = true;
    }
  }

So I got to wondering if I could divine anything meaningful from the errors reported by SocketConnector. I re-ran the tests with the following change in place:

   static void on_socket_closed(SocketConnector* connector, bool* is_closed) {
+    FAIL() << "Socket error code: " << connector->error_code() << ", error message: " << connector->error_message();
     if (connector->error_code() == SocketConnector::SOCKET_ERROR_CLOSE) {
       *is_closed = true;
     }

This offered up the following very interesting result:

[ RUN      ] SocketUnitTest.SslEnforceTlsVersion
/work/git/cpp-driver/tests/src/unit/tests/test_socket.cpp:185: Failure
Failed
Socket error code: 8, error message: Error during SSL handshake: error:1417118C:SSL routines:tls_process_server_hello:version too low
/work/git/cpp-driver/tests/src/unit/tests/test_socket.cpp:432: Failure
Value of: is_closed
  Actual: false
Expected: true
[  FAILED  ] SocketUnitTest.SslEnforceTlsVersion (20 ms)

It appears that the client is detecting at SSL handshake time that the server doesn't support a TLS version it can work with. This results in a return of SocketConnector::SOCKET_ERROR_SSL_HANDSHAKE via SocketConnector::ssl_handshake(). Given the way the test is structured this result makes a great deal of sense, but what I simply do not understand is why this issue appears only on some platforms and not on others.

It seems like the simplest fix would be a custom callback fn in test_socket.cpp which checks for both possible error returns. I'd feel a lot better if we understood why different errors were returned on different platforms so that we could determine if any additional steps need to happen in the impl generally... but I'm not 💯 convinced that's required for this PR (that could perhaps be moved to follow-up work).

@FalacerSelene
Copy link
Contributor Author

@absurdfarce , happily, I've been able to use a public image of ubuntu 18 to replicate the test issue, and have made your 'simplest fix' suggested change which has fixed it at least on that system. I'm guessing that it's due to subtle changes in openssl between versions, but I'm nowhere near familiar enough with the openssl codebase to work that out quickly.

I can see that the jenkins job is still failing though, even with this change. Could you let me know what the new issue is?

@absurdfarce
Copy link
Collaborator

@FalacerSelene The remaining failure is for the build on CentOS 6. That distro is EOL and it's use in our build matrix will likely be removed soon so it's not something I'm worried about. I'm doing some planning for the next release and would definitely like to include this change in that release so I'm good with merging it now. If the CentOS 6 failure becomes an issue I'll fix it later.

Thanks again for all your work (and your patience!) on this effort!

@absurdfarce absurdfarce merged commit 7cfa33d into datastax:master Apr 20, 2022
@kw217
Copy link
Contributor

kw217 commented Mar 13, 2023

@mpenick any chance of a new release with this change included?

@absurdfarce
Copy link
Collaborator

Hey @kw217, thanks for the question! We're definitely aware that we haven't had a release of the C/C++ driver in a while and have consequently built up a bit of a backlog. We're working on a number of time-sensitive issues at the moment but my hope is to clean out that backlog with a new release sometime this summer.

Thanks again!

@kw217
Copy link
Contributor

kw217 commented Mar 14, 2023

Thanks @absurdfarce. We are currently building off main, but would be much happier taking a tagged release. A summer release sounds good.

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.

4 participants