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

rumqttc: add TLS using OpenSSL, without going through native-tls #744

Open
Stupremee opened this issue Nov 4, 2023 · 9 comments
Open

rumqttc: add TLS using OpenSSL, without going through native-tls #744

Stupremee opened this issue Nov 4, 2023 · 9 comments

Comments

@Stupremee
Copy link

Hey,

I know this seems like an unusual feature request, because rumqttc already supports OpenSSL TLS using the native-tls.
However, in some edge case, I encountered while working with rumqttc and Azure IoT, I was forced to fork rumqtt and add the OpenSSL TLS option.

The edge case I encountered was the following. I have an Azure IoT Hub instance set up, and wanted to authenticate my devices using X.509 Client authentication. On the device, I used the Azure IoT Identity Service that manages the keys and certificates that my applications running on the device will use.
Now the part where the trouble began. If your application authenticates using the IoT Identity Service, it will never get access to the private key. Instead, you only get a Key Hande / Key ID which can then be used using an OpenSSL Engine.

That means I have a raw openssl::PrivateKey which can not be represented in DER format. So I need a TlsConfiguration::OpenSSL(openssl::ssl::SslConnector) (or something similar), where I can provide the raw OpenSSL private key to use for client authentication.

Proposed Solution

Add a use-openssl feature, that will add a TlsConfiguration::OpenSsl variant.
In the variant one can provide a openssl::ssl::ConnectConfiguration (or something else, this can be discussed).
This allows the user to use a raw openssl::pkey::PKey for client authentication.

I understand that this is an edge case, and you might not want to add this to rumqttc, which I totally understand.
However, it would be really nice for me since then I don't have to use a custom fork :)

@swanandx
Copy link
Member

Hey, I had some doubts:

  • wdym by "raw openssl::PrivateKey" ?
  • pkey::PKey needs to be created somehow right? how would you create it?
  • will using rustls instead of native-tls help?

thanks :)

@Stupremee
Copy link
Author

Hi,

Sorry it might have been badly phrased.

What I mean is, that I have a PKey<Private> that is constructed by an OpenSSL engine (using with this method).
Resulting from this, the PKey is not able to be serialized to DER format, thus can not be passed into TlsConfiguration::SimpleNative.

Rustls wouldn't help because I need to use an OpenSSL engine for the private key operations.

It's a rare edge case, I know!

@swanandx
Copy link
Member

swanandx commented Nov 23, 2023

but it does have a function to convert into der: private_key_to_der

Other conversations are there as well! So i believe you can convert it to der for native-tls, or even to pemfile for rustls.

@swanandx
Copy link
Member

swanandx commented Nov 23, 2023

What I mean is, that I have a PKey that is constructed by an OpenSSL engine (using with this method).

can you please share example rust code? I'm confused as PKey doesn't have any method corresponding to ENGINE_load_private_key method 😅 just curious haha

@Stupremee
Copy link
Author

but it does have a function to convert into der: private_key_to_der

Other conversations are there as well! So i believe you can convert it to der for native-tls, or even to pemfile for rustls.

If you call that with a PKey that comes from an OpenSSL engine, it wil lfail.

What I mean is, that I have a PKey that is constructed by an OpenSSL engine (using with this method).

can you please share example rust code? I'm confused as PKey doesn't have any method corresponding to ENGINE_load_private_key method 😅 just curious haha

Unfortunaly, the openssl crate does not implement bindings for Engines. But you can have a look at this crate where they implement bindings for OpenSSL engines.

@swanandx
Copy link
Member

If you call that with a PKey that comes from an OpenSSL engine, it wil lfail.

Any reasons to fail? also, does converting to pemfile / other formats fail as well?

Unfortunaly, the openssl crate does not implement bindings for Engines. But you can have a look at this crate where they implement bindings for OpenSSL engines.

Okie! Thanks for sharing.

@Stupremee
Copy link
Author

Stupremee commented Nov 23, 2023

Any reasons to fail? also, does converting to pemfile / other formats fail as well?

Yes it does, because the key is not a real private key, instead it's some unique ID and an "Engine". The Engine can then use the ID to perform all the signing operations.

A more common use-case of OpenSSL Engines are Yubikeys / HSMs. These are implemented using OpenSSL engines.

Here are some examples for yubikeys

@swanandx
Copy link
Member

because the key is not a real private key, instead it's some unique ID and an "Engine".

Job of engine should be done by we get the pkey right? As per the crate you shared which called ENGINE_load_key, it uses that ID & engine and returns pkey::Pkey<Private>, which should be the actual key ( EVP_KEY ).

Can you please confirm once what errors are you getting? And is there a way to reproduce this issue to debug further?

Thank you so much 😁

@Stupremee
Copy link
Author

Stupremee commented Apr 16, 2024

Hey @swanandx,

sorry for the long delay here, but I totally forgot I had this issue and we were fine using a small custom fork of rumqttc for our needs.

Job of engine should be done by we get the pkey right? As per the crate you shared which called ENGINE_load_key, it uses that ID & engine and returns pkey::Pkey, which should be the actual key ( EVP_KEY ).

Yes that's right, the engine establishes the private key, however, the private key can not be serialized, as it may be stored on an HSM and be inaccessible for the user. So the engine's job is to overwrite all sign / encrypt / etc operations to use the underlying HSM. That's the reason functions like serializing to DER will fail, and without the possibility to serialize it, it's impossible to pass into the TlsConfiguration::Native / TlsConfiguration::SimpleNative configuration.

Anyway, I actually found another use case for which I still need my custom fork at the moment. My MQTT server has a custom, self-signed root certificate, which I'm unable to mark as trusted in the standard rumqttc version. You could achieve this using native-tls, which would be fine too.

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

No branches or pull requests

2 participants