Dealing with untrusted TLS certificates in a QML only plasmoid

Dear all,

I have a rather popular third party plasmoid that I am currently porting to Plasma6.

The issue that I am facing: that plasmoid communicates with a device (a Philips / Signyfy Hue Bridge Pro) that uses a certificate by a CA not trusted on any OS, and obviously with a “wrong” certificate subject.

I am using XMLHttpRequest ( XMLHttpRequest QML Type | Qt Qml | Qt 6.9.2 ) to call that devices REST API, and due to a 301 by the device, https is enforced. Now QML quite silently fails if it does a TLS request to a certificate it doesn’t trust, and there seems to be no option to disable that.

Now what should I do?

Requirement:

  • I need to talk to https. You can’t enforce http, you can’t disable https
  • I do have the CA (Philips provides it) that I could inject. However, the certificate subject would obviously still be wrong, as that device has an IP and not a name, and that IP is different for everyone
  • I can’t install the CA as a OS trusted CA, and even if I could, see above, certificate subject
  • I can’t use C++ (or any other, non-qml) code, since the plasmoid should be distributable via KDE store / get hot new stuff etc., so only plain qml allowed

So basically I need a way in pure QML to disable TLS verification in XMLHttpRequest or do a simple http(s) request that returns json without TLS vertification.

I know that this defeats the purpose of TLS and is insecure, please no discussions about that, since I can’t change the world or a multi-billion company such as Philips / Signyfy, but I would like the plasmoid to be usable again, as it seems quite a lot of people installed and liked it.

Thanks in advance for solutions, hints or ideas.

Fox

What does the original code do that you are porting from?

I am not familiar with the store, however I would guess that a package distributed through it could include other interpreted code, e.g. Python.

It is also possible that you are not the first person trying to interact with the device from a Linux system.
Others could have already written software that the Plasmoid could interact with or which could be extended to enable such interaction.

E.g. the device sounds like something Home Assist could have support for.

Obviously not everyone with such a device would be running Home Assist but it might be possible to write a session (or even system) service with a similar interface so that the Plasmoid could work with either.

Multiple Plasmoid instances wouldn’t all need to interact with the device individually and alternative UIs would be possible (e.g. applications, GNOME Shell Extension, etc).

If none of those approaches are viable you could try using a QtQuick WebEngineView.
It allows to accept a certificate that generated an error.

Be prepared to get lots of negative publicity by people who don’t understand why you are doing this and what the impact is.

What does the original code do that you are porting from?

The exact same. The original code is mine as well, I just haven’t touched that plasmoid in a year or so, now I do. Could have omitted that info, I guess.

I am not familiar with the store, however I would guess that a package distributed through it could include other interpreted code, e.g. Python.

Potentially, and I could most likely ship it with a helper binary of sorts and call that, but that’s imho very hacky and a bad idea, since I can’t know if / what interpreter is installed on the target system. Thus I would have preferred something in pure QML, relying only on what KDE Plasma already brings along.

It is also possible that you are not the first person trying to interact with the device from a Linux system.

There are plenty of other apps for it, but afaik none written in QML, thus none with that silly restriction. From what I’ve seen, some inject the Philips / Signyfy CA and/or disable TLS verification, which apparently QML does not offer

Obviously not everyone with such a device would be running Home Assist but it might be possible to write a session (or even system) service with a similar interface so that the Plasmoid could work with either.

It has full HA support, but that’s again a third party dependency that I’d like to avoid.

The idea of that plasmoid is that you can simply pull it in and interact with your smart lights, without having to rely on services or binaries you have to install with whatever means your operating system supports. And up to recently, this was possible, and now it isn’t as QML is a bit super strict (understandably) with no paths to work around that, that I can see (less understandably, thus asking here)

If none of those approaches are viable you could try using a QtQuick WebEngineView.
It allows to accept a certificate that generated an error.

Thanks a lot, I shall look into that, if it can work in the background and if I can extract the json the API gives from it, that might work. It sounds a bit like a massive overkill, but if there is no other solution I am willing to try!

As for the publicity part: I can add a note to the readme, but to be honest, almost every single other workaround or even solution to do it is just about as bad, and I think that’s to blame on Signyfy / Philips and their recent change, plus QML offering no decent way to inject custom CAs (that would be the secure and sane option) and disable parts of the validation (specifically the subject)

Apparently this is an oversight in Qt, see https://bugreports.qt.io/browse/QTBUG-140519, and I assume this will be fixed in a future version. However, knowing Qt and its development process, I expect that to take a few months, and then another few for that to land in distributions.

So I guess in the meantime I’ll do an extra ugly and indeed ship a little external helper (most likely pythong, despite the extra dependency) and use the Plasma5 external executable data source. Shame, but probably the only solution that works.

I think that was valuable information.
It meant that either API or implementation changed. I take it from your other comment that it was the latter?

Interesting. I would consider this sort of separation the cleaner approach.
Keeping as much “logic” out of QML as possible, especially as much I/O and data processing as possible.

That is of course a valid problem.
Ideally they host would either guarantee some of these runtimes or be able to install them automatically.

Yes, however the issue is that XMLHttpRequest should never have been part of QtQml.
Remote I/O should not be accessible from the UI without the application core knowing about it.
Sure, the host (in this case Plasma) can intercept this with URL interceptors but I am not sure Plasma installs any of those.

Better to not expose that at all, especially since most (if not all) Plasma applets run inside the same process.

That sounds like the most reasonable approach.
You only need to verify the validity of the “server” certificate against your know counterpart and can still get an encrypted channel.

I understand that this would not be the primary target.

What I meant is that if such integrations exist it would be valuable if the Plasma UI could use those when they are present.
Hence the idea of a “local” service which would be similar (or even identical) as far as API/communication is concerned so that the UI could work with either.

I don’t think it needs to be visible to work and it can certainly execute JavaScript on the loaded content. Can even do a QWebChannel between “host” and “web” side.

Yes, it probably is. Was just brainstorming other options :slight_smile: