mqtt_cpp icon indicating copy to clipboard operation
mqtt_cpp copied to clipboard

Add support for GnuTLS

Open shantanu1singh opened this issue 4 years ago • 28 comments

Add support for GnuTLS

The feature is controlled through the variable MQTT_USE_GNU_TLS. MQTT_USE_TLS also needs to be enabled for this feature to work.

If MQTT_USE_GNU_TLS is disabled and MQTT_USE_TLS is enabled, mqtt_cpp will use OpenSSL instead of GnuTLS

shantanu1singh avatar Sep 18 '20 17:09 shantanu1singh

Related to issue #662

shantanu1singh avatar Sep 18 '20 17:09 shantanu1singh

I have two suggestions

  1. Can you re-write your git-history to be a bit more concise? E.g. "Working changes" seems like it could have been merged into a different commit.

  2. What do you think about using MQTT_TLS_IMPL=GnuTLS instead of MQTT_USE_GNU_TLS=ON ? MQTT_TLS_IMPL would default to OpenSSL, but then other implementations could be provided without needing to add more and more build-options.

jonesmz avatar Sep 18 '20 18:09 jonesmz

I have two suggestions

1. Can you re-write your git-history to be a bit more concise? E.g. "Working changes" seems like it could have been merged into a different commit.

I think this order of doing things makes sense, to me anyway,

  1. Add the tls_implementation.h file and have only the macros needed for openssl.
  2. Introduce the "tls" namespace, convert all locations where as::ssl is used.
  3. Any places in the code that need to behave differently based on the ssl implementation, should have free-standing functions that take the appropriate arguments added, and be converted to use those free functions. Implement only the OpenSSL logic at this point.
  4. Adjust tls_implementation.h to support also the GnuTLS implementation. Adjust the various ifdefs, macros, namespaces, and free functions. This commit would have no changes happen to the main mqtt_cpp code, only the tls_implementation.h file
  5. Add unit tests and cmake infastructure.

jonesmz avatar Sep 18 '20 18:09 jonesmz

Codecov Report

Merging #663 into master will increase coverage by 0.55%. The diff coverage is 100.00%.

@@            Coverage Diff             @@
##           master     #663      +/-   ##
==========================================
+ Coverage   82.13%   82.68%   +0.55%     
==========================================
  Files          45       46       +1     
  Lines        7012     7076      +64     
==========================================
+ Hits         5759     5851      +92     
+ Misses       1253     1225      -28     

codecov[bot] avatar Sep 18 '20 18:09 codecov[bot]

@shantanu1singh , I'm not sure the current situation. Could you rebase the PR from the new master and cleanup commit history ?

When you add new concurrent builds, you need to avoid queuing. Because it makes longer CI times. It depends on github actions. So please check the number of maximum concurrent tasks. I think that it is independently limited by osx, linux, and windows. So far, windows build is not used on github actions. It is implemented azure pipelines. The reason I use the azure pipelines, it is for faster CI times. I want to avoid queuing tasks.

For gnutls, I think that the following tests are good enough. They are focused on connecting sequence.

https://github.com/redboltz/mqtt_cpp/blob/master/test/connect.cpp https://github.com/redboltz/mqtt_cpp/blob/master/test/underlying_timeout.cpp

I think that other part of the code, there is no difference between gnutls and openssl.

The tests are grouped in MQTT_TEST_1.

You need to add only one line that contains MQTT_TEST_1 and gnutls setting for each os. Other tests and example should be OFF.

redboltz avatar Sep 23 '20 00:09 redboltz

@redboltz, I'm a bit preoccupied with work. I'll get back to this PR sometime next week or the one after. I'll update the PR with rebased commits too. Currently running into a problem with some test failures so I need to debug those.

You need to add only one line that contains MQTT_TEST_1 and gnutls setting for each os. Other tests and example should be OFF.

Sounds good, I'll use just those tests then for gnutls

shantanu1singh avatar Sep 24 '20 00:09 shantanu1singh

@redboltz, I'm a bit preoccupied with work. I'll get back to this PR sometime next week or the one after.

No problem. Take your time.

As https://github.com/redboltz/mqtt_cpp/pull/663#issuecomment-695009683 commented, you can do that as follows:

See "Compiler options:" textbox on the left side of the code.

Compiler option Result
no tls option https://wandbox.org/permlink/z5FhFWckXyRMpgmE
-DMQTT_USE_TLS https://wandbox.org/permlink/ejf6fahORc0zPKVN
-DMQTT_USE_TLS=MQTT_TLS_OPENSSL https://wandbox.org/permlink/exmogJXC8Zti43SA
-DMQTT_USE_TLS=MQTT_TLS_GNUTLS https://wandbox.org/permlink/gjxyCDS6jQ3fwwnu

redboltz avatar Sep 24 '20 01:09 redboltz

@redboltz thanks for the tip! I'll use that

I had one question - With respect to including the headers in boost-asio-gnutls, the PR in it's current state assumes that the headers in this repo have been placed under the boost/asio directory on the machine.

I was wondering if it's a good idea to require consumers to mix default boost/asio headers with the headers from this repository. What do you think about introducing a new CMake Variable that allows consumers to specify the path to the directory boost-asio-gnu-tls on the consumer's machine? That way we can use the variable and add it to the include_directories path of the mqtt_cpp CMake if GNU TLS is enabled.

Something like:

-DWITH_BOOST_ASIO_GNU_TLS=/usr/local/include/boost-asio-gnutls

shantanu1singh avatar Sep 29 '20 17:09 shantanu1singh

@redboltz thanks for the tip! I'll use that

I had one question - With respect to including the headers in boost-asio-gnutls, the PR in it's current state assumes that the headers in this repo have been placed under the boost/asio directory on the machine.

I was wondering if it's a good idea to require consumers to mix default boost/asio headers with the headers from this repository. What do you think about introducing a new CMake Variable that allows consumers to specify the path to the directory boost-asio-gnu-tls on the consumer's machine? That way we can use the variable and add it to the include_directories path of the mqtt_cpp CMake if GNU TLS is enabled.

Something like:

-DWITH_BOOST_ASIO_GNU_TLS=/usr/local/include/boost-asio-gnutls

Hey @redboltz , what do you think about the above?

shantanu1singh avatar Oct 01 '20 00:10 shantanu1singh

@redboltz thanks for the tip! I'll use that I had one question - With respect to including the headers in boost-asio-gnutls, the PR in it's current state assumes that the headers in this repo have been placed under the boost/asio directory on the machine. I was wondering if it's a good idea to require consumers to mix default boost/asio headers with the headers from this repository. What do you think about introducing a new CMake Variable that allows consumers to specify the path to the directory boost-asio-gnu-tls on the consumer's machine? That way we can use the variable and add it to the include_directories path of the mqtt_cpp CMake if GNU TLS is enabled. Something like: -DWITH_BOOST_ASIO_GNU_TLS=/usr/local/include/boost-asio-gnutls

Hey @redboltz , what do you think about the above?

I think that it is a good idea. I think that MQTT_BOOST_ASIO_GNUTLS_INCLUDE is good name. Prefix MQTT is to avoid conflict. GNUTLS respects the repository name. *_INCLUDE is typical way to set include path on cmake.

redboltz avatar Oct 01 '20 02:10 redboltz

I ran into a problem with websocket based clients i.e., MQTT_USE_TLS combined with MQTT_USE_WS.

The header boost/beast/websocket/gnutls/ssl.hpp included in include/mqtt/ws_endpoint.hpp refers to boost/asio/ssl/stream.hpp. That's based on OpenSSL.

I had to update two headers of boost/beast/websocket to use the 'boost-asio-gnutls' headers instead and the updated files can be found here Is it acceptable to use the headers referred to in the linked repository in the mqtt_cpp library?

Essentially, we'll include the following headers in ws_endpoint.hpp (or rather tls_implementation.hpp), based on the appropriate SSL library:

OpenSSL

#include <boost/beast/websocket/ssl.hpp>

GnuTLS

#include <boost/beast/websocket/gnutls/ssl.hpp>

@redboltz @jonesmz any suggestions are welcome.

shantanu1singh avatar Oct 02 '20 21:10 shantanu1singh

Any chance of convincing boost beast to fix their header, instead of working around the problem in mqtt_cpp ?

jonesmz avatar Oct 02 '20 21:10 jonesmz

@jonesmz Not sure if they'd be accepting of that change so easily. They'd make the argument of updating boost/asio to add support for GnuTLS natively instead of leveraging a different repository 'boost-asio-gnutls' entirely.

shantanu1singh avatar Oct 02 '20 21:10 shantanu1singh

Ok.

Well, ultimately @redboltz makes the call.

My advice is that before this change is accepted into mqtt_cpp, the appropriate PRs to get GNUTls integrated into boost asio and boost beast be created, so that there's a roadmap in place for when the integration patches inside of mqtt_cpp can be dropped.

jonesmz avatar Oct 02 '20 21:10 jonesmz

@jonesmz Not sure if they'd be accepting of that change so easily. They'd make the argument of updating boost/asio to add support for GnuTLS natively instead of leveraging a different repository 'boost-asio-gnutls' entirely.

I think that it is better that boost asio and boost beast support gnutls directly. Because TLS support is very generic topic. If boost asio and beast users such as mqtt_cpp implements gnutls support individually, the situation would be confused (code duplication etc).

Do someone or you already proposed to boost to support gnutls ?

redboltz avatar Oct 05 '20 04:10 redboltz

I have some question about TLS and WesSocket combination. Now I'm checking on #673 . I guess that beast doesn't need to care about TLS because it is hidden underlying layer from the beast. Anyway please wait a moment.

Also I consider https://github.com/redboltz/mqtt_cpp/pull/663#issuecomment-702968043 comment. I'm looking for a good way.

redboltz avatar Oct 05 '20 09:10 redboltz

I guess that beast doesn't need to care about TLS because it is hidden underlying layer from the beast.

I was wrong. Due to very complected web socket and TLS tear down sequence, beast needs to care about TLS layer directly. Graceful shutdown is a headache on Websocket on TLS on TCP.

redboltz avatar Oct 05 '20 09:10 redboltz

@shantanu1singh , could you try #673 ?

As I commented at https://github.com/redboltz/mqtt_cpp/pull/663#issuecomment-703384855, GnuTLS support is implemented by boost asio and boost beast, not mqtt_cpp. So I implemented minimal support code for GnuTLS by mqtt_cpp.

You can test and use as follows.

cmake -DCMAKE_CXX_FLAGS="-DMQTT_TLS_INCLUDE=<boost/asio/gnutls.hpp> -DMQTT_TLS_WS_INCLUDE=<boost/beast/websocket/gnutls.hpp> -DMQTT_TLS_NS=boost::asio::gnutls" other_cmake_options... target_path

So you don't need to add tests. Just use #673 by your responsibility.

redboltz avatar Oct 05 '20 09:10 redboltz

@jonesmz Not sure if they'd be accepting of that change so easily. They'd make the argument of updating boost/asio to add support for GnuTLS natively instead of leveraging a different repository 'boost-asio-gnutls' entirely.

I think that it is better that boost asio and boost beast support gnutls directly. Because TLS support is very generic topic. If boost asio and beast users such as mqtt_cpp implements gnutls support individually, the situation would be confused (code duplication etc).

Do someone or you already proposed to boost to support gnutls ?

@redboltz No, I personally have not nor do I know of someone who did. The reason I started looking into it was just that we are using the mqtt_cpp library in our project and our customer doesn't wish to use OpenSSL. Getting support for GnuTLS incorporated into boost will likely be a bigger task I think. I might open a ticket on their repository to see how they feel about it

shantanu1singh avatar Oct 05 '20 16:10 shantanu1singh

I guess that beast doesn't need to care about TLS because it is hidden underlying layer from the beast.

I was wrong. Due to very complected web socket and TLS tear down sequence, beast needs to care about TLS layer directly. Graceful shutdown is a headache on Websocket on TLS on TCP.

@redboltz Could you possibly link me to some references that explain what you meant? Is there some teardown process that I would need to handle with GnuTLS if I use it with mqtt_cpp using #673 ?

shantanu1singh avatar Oct 05 '20 16:10 shantanu1singh

@shantanu1singh , could you try #673 ?

As I commented at #663 (comment), GnuTLS support is implemented by boost asio and boost beast, not mqtt_cpp. So I implemented minimal support code for GnuTLS by mqtt_cpp.

You can test and use as follows.

cmake -DCMAKE_CXX_FLAGS="-DMQTT_TLS_INCLUDE=<boost/asio/gnutls.hpp> -DMQTT_TLS_WS_INCLUDE=<boost/beast/websocket/gnutls.hpp> -DMQTT_TLS_NS=boost::asio::gnutls" other_cmake_options... target_path

So you don't need to add tests. Just use #673 by your responsibility.

@redboltz Thank you for sharing that. I can try using it. Although, would you be merging that PR with master?

shantanu1singh avatar Oct 05 '20 16:10 shantanu1singh

@shantanu1singh , could you try #673 ? As I commented at #663 (comment), GnuTLS support is implemented by boost asio and boost beast, not mqtt_cpp. So I implemented minimal support code for GnuTLS by mqtt_cpp. You can test and use as follows.

cmake -DCMAKE_CXX_FLAGS="-DMQTT_TLS_INCLUDE=<boost/asio/gnutls.hpp> -DMQTT_TLS_WS_INCLUDE=<boost/beast/websocket/gnutls.hpp> -DMQTT_TLS_NS=boost::asio::gnutls" other_cmake_options... target_path

So you don't need to add tests. Just use #673 by your responsibility.

@redboltz Thank you for sharing that. I can try using it. Although, would you be merging that PR with master?

Yes, if it works well on your environment. #673 is minimal support for alternative TLS library. The library needs to provide compatible interfaces as boost/asio/ssl.hpp and boost/beast/websocket/ssl.hpp.

redboltz avatar Oct 05 '20 23:10 redboltz

I guess that beast doesn't need to care about TLS because it is hidden underlying layer from the beast.

I was wrong. Due to very complected web socket and TLS tear down sequence, beast needs to care about TLS layer directly. Graceful shutdown is a headache on Websocket on TLS on TCP.

@redboltz Could you possibly link me to some references that explain what you meant? Is there some teardown process that I would need to handle with GnuTLS if I use it with mqtt_cpp using #673 ?

For example, boost beast directly use ssl feature as follows:

https://github.com/boostorg/beast/blob/develop/include/boost/beast/websocket/ssl.hpp https://github.com/boostorg/beast/blob/develop/include/boost/beast/websocket/impl/ssl.hpp

You might think why MQTT_TLS_WS_NS is not required. I guess that there is no explicit public interfaces for boost beast websocket (TLS) users. The special treatment requires only teardown process. I guess that teardown process is called from (some class') destructor automatically (implicitly).

Unfortunately, I don't know what kind of special treatment is required.

redboltz avatar Oct 06 '20 00:10 redboltz

@shantanu1singh, does #673 work well ?

redboltz avatar Oct 11 '20 11:10 redboltz

@redboltz I haven't had the chance to test it yet. Will likely get to it today or tomorrow. I'll keep you posted here.

shantanu1singh avatar Oct 12 '20 16:10 shantanu1singh

@redboltz I tried out #673 but it failed with an error. I've pointed out what needs to be changed in your PR. If you can help update that, I can give it another test. Thanks!

shantanu1singh avatar Oct 16 '20 22:10 shantanu1singh

This is the error just as a reference:

/home/shantanu/repos/mqtt_cpp_1/include/mqtt/endpoint.hpp: In member function ‘bool mqtt::endpoint<Mutex, LockGuard, PacketIdBytes>::handle_close_or_error(mqtt::error_code)’:
/home/shantanu/repos/mqtt_cpp_1/include/mqtt/endpoint.hpp:4567:17: error: there are no arguments to ‘ERR_GET_REASON’ that depend on a template parameter, so a declaration of ‘ERR_GET_REASON’ must be available [-fpermissive]
             || (ERR_GET_REASON(ec.value()) == boost::asio::ssl::error::stream_truncated)
                 ^~~~~~~~~~~~~~
/home/shantanu/repos/mqtt_cpp_1/include/mqtt/endpoint.hpp:4567:17: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
/home/shantanu/repos/mqtt_cpp_1/include/mqtt/endpoint.hpp:4567:60: error: ‘boost::asio::ssl’ has not been declared
             || (ERR_GET_REASON(ec.value()) == boost::asio::ssl::error::stream_truncated)

shantanu1singh avatar Oct 16 '20 22:10 shantanu1singh

Could you post a new PR to fix #673 ? The target branch is add_alt_tls_support.

redboltz avatar Oct 17 '20 01:10 redboltz