Azure / iot-identity-service

Source of the Azure IoT Identity Service and related services.
MIT License
37 stars 45 forks source link

Support RSA key exchange methods in OpenSSL engine and Key Service #495

Open quality-leftovers opened 1 year ago

quality-leftovers commented 1 year ago

Since we are already using aziot_keys engine on our edge to connect to IoT Hub we've been wondering if it would also be possible to use it as "crypto backend" for a web server certificate (TLS 1.2+). As far as I understand this is currently not possible since the OpenSSL engine and the key service do not implement "decrypt".

Therefore I'd like to know if you have any plans to add the required functions to key service and the OpenSSL engine, or if you would be interested in a PR (not sure if we have the time and rust skills required for that PR, though).

Greets

quality-leftovers commented 1 year ago

Hm I did some testing with an ASP .NET Core Server connected to the key service and I'm a bit confused now.

I expected it to fail for TLS 1.2 due to the missing decrypt during pre-master secret exchange, but it actually works. So it seems some other algorithm was used during that exchange / handshake? I thought only for TLS 1.3 the server would not need to decrypt something. So I'm happy that it worked, but unhappy that I don't understand why it did so far and also don't know how algorithms are selected, etc.

The only thing that was blocking me initially was that my test setup created a self signed cert using .NET libraries and the .NET crypto libraries refused to "do the sign" until I added openssl_sys2::RSA_set_flags(parameters, RSA_FLAG_EXT_PKEY) to engine_load_privkey in the OpenSSL engine.

quality-leftovers commented 1 year ago

Okay, so I think I've really missed all important stuff in the docs. It seems there are tests for use of server certificates and even a sequence diagram that shows edge hub retrieving a server certificate.

Also it seems that I probably just need to configure openssl using an openssl.cnf so that only ciphers that work are offered to clients.

What I'm still not sure is what aside from implementing /decrypt I'd need to do to support the ciphers with key exchange RSA (for legacy clients). I implemented /decrypt for RSA and it it works via OpenSSL engine, but is not called when a client tries to connect using a cipher with RSA key exchange. I assume that the problem here is down to me not understanding how OpenSSL works and what an engine needs to do to support such a cipher. I'll work on my understanding, before bothering you futher :)

onalante-msft commented 1 year ago

Sorry I missed this. I am not too sure myself what the exact process to get /decrypt working with a custom engine is. @arsing would know best on account of having written the aziot-keys OpenSSL engine subsystem, but they are currently out until 30-12-2022. I am not sure whether I can get to this before then since other bugs are currently occupying my time, but I will take a look if my workload clears up.

arsing commented 1 year ago

It seems there are tests for use of server certificates [...]

Yes, https://github.com/Azure/iot-identity-service/blob/main/key/test-aziot-key-openssl-engine-shared.sh

[...] and even a sequence diagram that shows edge hub retrieving a server certificate.

Which diagram is that? If you mean https://github.com/Azure/iot-identity-service/blob/main/docs-dev/openssl-engine-internals.md that is not about Edge Hub, just an arbitrary client. Edge Hub's server cert does not have a key backed by the OpenSSL engine, because Edge modules like Edge Hub do not have access to the Keys Service to be able to do key operations. Edge modules get certs with the keys in plaintext via the edged workload API.

I expected it to fail for TLS 1.2 due to the missing decrypt during pre-master secret exchange, but it actually works. So it seems some other algorithm was used during that exchange / handshake?

Decrypting with the RSA private key (RSA_priv_dec) is indeed not implemented ( https://github.com/Azure/iot-identity-service/blob/0236a869c36d6ee5745ac75538172af130cd4e7b/key/aziot-key-openssl-engine/src/rsa.rs#L131-L141 ). It would only be used in RSA handshakes, and openssl prefers DH handshakes (as it should) which do not require decrypting the pre-master secret with the private key.

Note that the key exchange algorithm is unrelated to the key algorithm of the certificate. ie the fact that your cert has an RSA key does not mean the key exchange algorithm must be RSA.

What I'm still not sure is what aside from implementing /decrypt I'd need to do to support the ciphers with key exchange RSA (for legacy clients).

Do you really have clients that require RSA key exchange ciphersuites because they don't support DH? I'd really rather not implement RSA_priv_dec in keyd.

quality-leftovers commented 1 year ago

It seems there are tests for use of server certificates [...]

Yes, https://github.com/Azure/iot-identity-service/blob/main/key/test-aziot-key-openssl-engine-shared.sh

[...] and even a sequence diagram that shows edge hub retrieving a server certificate.

Which diagram is that? If you mean https://github.com/Azure/iot-identity-service/blob/main/docs-dev/openssl-engine-internals.md that is not about Edge Hub, just an arbitrary client. Edge Hub's server cert does not have a key backed by the OpenSSL engine, because Edge modules like Edge Hub do not have access to the Keys Service to be able to do key operations. Edge modules get certs with the keys in plaintext via the edged workload API.

Thanks for clarification. I just thought that the KS was used by all components in est diagram since KS is not shown for connection to DPS. Probably didn't think too hard since the diagram clearly shows that the EdgeHub receives server cert + private key which makes no sense for KS keypairs.

I expected it to fail for TLS 1.2 due to the missing decrypt during pre-master secret exchange, but it actually works. So it seems some other algorithm was used during that exchange / handshake?

Decrypting with the RSA private key (RSA_priv_dec) is indeed not implemented (

https://github.com/Azure/iot-identity-service/blob/0236a869c36d6ee5745ac75538172af130cd4e7b/key/aziot-key-openssl-engine/src/rsa.rs#L131-L141

). It would only be used in RSA handshakes, and openssl prefers DH handshakes (as it should) which do not require decrypting the pre-master secret with the private key. Note that the key exchange algorithm is unrelated to the key algorithm of the certificate. ie the fact that your cert has an RSA key does not mean the key exchange algorithm must be RSA.

What I'm still not sure is what aside from implementing /decrypt I'd need to do to support the ciphers with key exchange RSA (for legacy clients).

Do you really have clients that require RSA key exchange ciphersuites because they don't support DH? I'd really rather not implement RSA_priv_dec in keyd.

Our edge is running in a factory and offers services to third party client applications. At times these software components run on machines that are up to 30 years old and while obviously there is a cut off (e.g. not supporting TLS 1.1) we'd like to offer "good old plain RSA" ciphersuites which is still better than doing no TLS at all.

I'd like to add that the setups with such old machines I've seen so far usually had pretty tight networking setups with hardware firewalls blocking all TCP connections to machines and only allowing outgoing TCP connections from machines to specific "safe" endpoints, so it's not the typical scenario of running a "weak(er)" TLS over the internet.

quality-leftovers commented 1 year ago

In case anyone else needs RSA decrypt for some reason I tried to implement it: https://github.com/quality-leftovers/iot-identity-service/tree/feat/rsadec. It seems to be working, luckily almost all stuff needed was already in place so even with my limited rust knowledge I was able to do it.

Only manually tested encrypt/decrypt via the OpenSSL engine yet, though and no automated tests of course :).