Skip to content

Commit 8672051

Browse files
authored
Provide instructions for TLS configuration (#20619)
Resolves #20199 Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
1 parent b926e4c commit 8672051

3 files changed

Lines changed: 79 additions & 3 deletions

File tree

bundles/org.openhab.binding.irobot/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,42 @@ The easiest way to determine the pmapId, region_ids/zoneids and userPmapvId is t
169169
1. Roomba's built-in MQTT server, used for communication, supports only a single local connection at a time. Bear this in mind when you want to do something that requires local connection from your phone, like reconfiguring the network. Disable openHAB Thing before doing this.
170170
1. Sometimes during intensive testing Roomba just stopped communicating over the local connection. If this happens, try rebooting it. On my robot it's done by holding "Clean" button for about 10 seconds until all the LEDs come on. Release the button and the reboot tone will be played. It looks like there are some bugs in the firmware.
171171

172+
### TLS Compatibility Issue
173+
174+
The Thing may go OFFLINE (COMMUNICATION_ERROR) with:
175+
176+
> Required TLS cipher (TLS_RSA_WITH_AES_256_CBC_SHA) is disabled by your Java security settings.
177+
178+
Some Roomba models use an outdated TLS configuration and require the legacy cipher `TLS_RSA_WITH_AES_256_CBC_SHA`.
179+
180+
Starting with OpenJDK 21.0.10 (and corresponding distributions such as Eclipse Temurin 21.0.10), Java disables all `TLS_RSA_*` cipher suites by default via the `jdk.tls.disabledAlgorithms` setting.
181+
As a result, connections to devices relying on these ciphers (such as some Roomba models) will fail.
182+
183+
To allow the connection, you must re-enable this cipher in Java’s TLS configuration.
184+
185+
:::warning
186+
Re-enabling `TLS_RSA_WITH_AES_256_CBC_SHA` has security implications:
187+
188+
- No forward secrecy (RSA key exchange)
189+
- Uses older CBC-based cipher
190+
- Considered deprecated in modern TLS standards
191+
192+
Only enable this on trusted/local networks.
193+
:::
194+
195+
To proceed, modify the system Java configuration by editing (for example) `/usr/lib/jvm/temurin-21-jre-arm64/conf/security/java.security` and adjust the `jdk.tls.disabledAlgorithms` setting with the following contents:
196+
197+
```ini
198+
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \
199+
MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
200+
ECDH, TLS_RSA_WITH_AES_128_*, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384, rsa_pkcs1_sha1 usage HandshakeSignature, \
201+
ecdsa_sha1 usage HandshakeSignature, dsa_sha1 usage HandshakeSignature
202+
```
203+
204+
:::warning
205+
This change affects all Java applications on the system and requires a restart of openHAB.
206+
:::
207+
172208
## Example
173209

174210
### `irobot.things` Example

bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/handler/IRobotConnectionHandler.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.net.InetAddress;
2121
import java.net.UnknownHostException;
22+
import java.security.Security;
2223
import java.util.concurrent.CompletableFuture;
2324
import java.util.concurrent.ExecutionException;
2425
import java.util.concurrent.Future;
@@ -91,8 +92,16 @@ public synchronized void connect(final String ip, final String blid, final Strin
9192
connectionStateChanged(MqttConnectionState.DISCONNECTED, exception);
9293
return false;
9394
}).thenAccept(successful -> {
94-
MqttConnectionState state = successful ? MqttConnectionState.CONNECTED : MqttConnectionState.DISCONNECTED;
95-
connectionStateChanged(state, successful ? null : new TimeoutException("Timeout"));
95+
if (successful) {
96+
connectionStateChanged(MqttConnectionState.CONNECTED, null);
97+
} else {
98+
if (isRsaAes256CbcShaAvailable()) {
99+
connectionStateChanged(MqttConnectionState.DISCONNECTED, new TimeoutException("Timeout"));
100+
} else {
101+
connectionStateChanged(MqttConnectionState.DISCONNECTED, new SecurityException(
102+
"Required TLS cipher (TLS_RSA_WITH_AES_256_CBC_SHA) is disabled by your Java security settings."));
103+
}
104+
}
96105
});
97106

98107
this.connection = connection;
@@ -175,4 +184,30 @@ public void send(final String topic, final String payload) {
175184
connection.publish(topic, payload.getBytes(UTF_8), connection.getQos(), false);
176185
}
177186
}
187+
188+
/**
189+
* Check if the cipher suite <code>TLS_RSA_WITH_AES_256_CBC_SHA</code> is available.
190+
*
191+
* @return true if the cipher suite is available, false otherwise
192+
*/
193+
private boolean isRsaAes256CbcShaAvailable() {
194+
String disabledAlgorithms = Security.getProperty("jdk.tls.disabledAlgorithms");
195+
if (disabledAlgorithms == null || disabledAlgorithms.isBlank()) {
196+
return true;
197+
}
198+
logger.debug("jdk.tls.disabledAlgorithms: {}", disabledAlgorithms);
199+
200+
for (String token : disabledAlgorithms.split(",")) {
201+
token = token.trim();
202+
203+
switch (token) {
204+
case "TLS_RSA_*":
205+
case "TLS_RSA_*_SHA":
206+
case "TLS_RSA_WITH_AES_256_*":
207+
case "TLS_RSA_WITH_AES_256_CBC_SHA":
208+
return false;
209+
}
210+
}
211+
return true;
212+
}
178213
}

bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/handler/RoombaHandler.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ public void connectionStateChanged(MqttConnectionState state, @Nullable Throwabl
123123
} else {
124124
String message = (error != null) ? error.getMessage() : "Unknown reason";
125125
updateStatus(OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
126+
if (error instanceof SecurityException) {
127+
logger.warn(
128+
"TLS_RSA_WITH_AES_256_CBC_SHA is disabled by Java TLS policy (jdk.tls.disabledAlgorithms), canceling reconnection attempts. Please consult binding documentation.");
129+
dispose();
130+
}
126131
}
127132
}
128133
};
@@ -148,7 +153,7 @@ public void initialize() {
148153
public void dispose() {
149154
Future<?> requester = credentialRequester;
150155
if (requester != null) {
151-
requester.cancel(false);
156+
requester.cancel(true);
152157
credentialRequester = null;
153158
}
154159

0 commit comments

Comments
 (0)