After upgrading from openHAB 5.1.3 to 5.2.0, a JS rule that talks directly to my Philips Hue Bridge over its local HTTPS API (not via the official Hue binding) started failing with:

[ERROR] [enhab.core.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.ExecutionException: javax.net.ssl.SSLHandshakeException: (certificate_unknown) PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

This worked fine on 5.1.3. The calls use actions.HTTP.sendHttpGetRequest() / sendHttpPutRequest() against https://<bridge-ip>/api/..., which presents a self-signed certificate (standard behavior for local Hue Bridge HTTPS access).

The official Hue binding has a useSelfSignedCertificate option for exactly this scenario, but that doesn’t apply here since I’m calling the bridge’s REST API directly from a script, not through the binding. There also doesn’t appear to be an equivalent “ignore SSL errors” option for the actions.HTTP scripting actions (unlike the HTTP binding, which has ignoreSSLErrors=true).

Question: Did the underlying Jetty HTTP client’s certificate validation become stricter in 5.2.0? Is there a supported way to make actions.HTTP.sendHttpGetRequest/PutRequest trust a specific self-signed certificate (or ignore SSL errors) without manually importing it into the JVM’s cacerts keystore?

That’s likely. That’s the kind of thing they always restrict more and more, also “banning” older encryption algorithms and generally making things harder in the name of “safety”. I can’t say specifically that this is the case here, but I see at as very plausible.

I’ve looked at bit in the code, and it seems that the answer is no. There’s nothing that deals with SSL at all in the class that provides the HTTP actions. But, worse than that, we can’t really change it either, at least not without some major rewriting.

The reason is that to make Java “trust” self-signed, “deprecated” algorithms and similar, you must configure the HTTP client to do so (with ample warnings logged about the huge risk etc.). You can’t make it only ignore it for a specific call only. The HTTP actions, since they can be called to do stuff at any time, don’t “own” their own HTTP clients. Instead, they get and use HTTP clients as needed from a pool of “common HTTP clients”. These can’t, for obvious reasons, but configured to ignore certificate issue (or it would apply to all kind of things).

Enabling the HTTP actions to do this, would require them to somehow have some “ready configured” HTTP clients hanging around just in case they needed to make calls with more lenient SSL enforcement. As mentioned above, only creating these instances will make Java log “scary log entries about risk and blah, blah”, that I’m sure would scare some users. And, these would have nothing to do most of the time, and would be a waste of resources.

I guess some intricate way to only spawn one if requested would be possible, but it could get complicated - having only one system-wide might not be enough. Also, there are several “switches” you can turn on and off regarding SSL enforcement, it’s not just ON and OFF. So, I don’t quite see how this could be arranged without drawbacks and complications.

The only thing I can think of is that you create your own HTTP client in the script, but make sure to terminate is properly after use. It should be something like this:

val secureClient = new HttpClient(new SslContextFactory.Client(true))
try {
    // Do stuff
} finally {
    secureClient.stop()
}

Thanks for the detailed explanation — that matches exactly what I found. Since actions.HTTP uses a shared pool of common HTTP clients (not a per-call client), there’s no way to relax SSL/hostname checks for just one target without affecting all HTTP traffic.

For anyone hitting the same issue (self-signed Hue Bridge certificate with no Subject Alternative Name, failing after 5.1.3 → 5.2.0 with No subject alternative names present): I bypassed actions.HTTP entirely for the bridge calls and built a small helper in the JS rule using direct Java interop, since openhab-js runs on GraalVM and gives access to Java classes via Java.type():

const JavaURL            = Java.type("java.net.URL");
const HttpsURLConnection = Java.type("javax.net.ssl.HttpsURLConnection");

const HUE_BRIDGE_HOSTS = ["192.168.x.x", "192.168.x.x"]; // your bridge IPs

function hueHttpRequest(urlString, method, contentType, body, timeoutMs) {
    const url = new JavaURL(urlString);
    const conn = url.openConnection();

    if (conn instanceof HttpsURLConnection && HUE_BRIDGE_HOSTS.includes(url.getHost())) {
        conn.setHostnameVerifier(function (hostname, session) { return true; });
    }
    conn.setRequestMethod(method);
    conn.setConnectTimeout(timeoutMs);
    conn.setReadTimeout(timeoutMs);
    // ... write body if present, read response, return as string
}

Two things worth noting:

  • The certificate itself is still validated normally (imported into the container’s Java truststore via update-ca-certificates) — only the hostname/SAN check is skipped, and only for these two specific IPs. No global relaxation of SSL enforcement.
  • This creates its own HttpsURLConnection per call rather than touching the shared HTTP client pool, so it doesn’t carry the resource/logging concerns you described for a system-wide solution.

Works reliably on 5.2.0. Sharing in case it saves someone else the same troubleshooting.

It seems like we basically got the same idea, mine is just “concept code” for DSL, while you used JS. In either case, you probably need to close/stop it after use to avoid resource leak.

Out of curiosity, what the crypto policy configured that you are running with? You can find in in /etc/defaults/openhab (or something like that). If it’s “limited” the error might be relevant here. The problem isn’t that self signed certs are not allowed but that the two sides of the connection cannot negotiate an encryption protocol for the TLS traffic.

On another thread it was discovered that browsers and others have dropped support for TLS 1.2 (IIRC, could be wrong on the version number here) and TLS 1.3 doesn’t support any of the limited encryption protocols any more. Changing to unlimited will enable OH to use the better encryption and establish the connection.

Thanks for the pointer! I checked — I’m running OpenHAB 5.x on Java 21, and unlimited crypto strength has been the default since Java 9, so I don’t think the crypto.policy setting itself was misconfigured on my end. The specific error I hit (No subject alternative names present) also looks like a hostname-verification failure rather than a cipher-negotiation one, which points more toward the Hue Bridge’s self-signed cert simply lacking a SAN entry (confirmed via openssl x509 -noout -ext subjectAltName, which returned nothing). I ended up working around it by bypassing the shared HTTP client actions.HTTP uses and building a small custom HTTPS call in the JS rule itself, with hostname verification disabled only for the bridge’s IP. Appreciate you digging into this though — good to have crypto.policy on the radar for anyone hitting a different flavor of this issue.

Until very recently (the last week or so) limited was the default for the openHAB Docker image.