Skip to content

Commit 1d8fa50

Browse files
[knx] Add support for using hardware TPM modules
Add TpmInterface, a class built on top of Tss.Java. This lib is to be included in a special way due to inconsistencies in package creation which makes it incompatible to OSGI. Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
1 parent f6e750a commit 1d8fa50

8 files changed

Lines changed: 575 additions & 5 deletions

File tree

bundles/org.openhab.binding.knx/pom.xml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,87 @@
4949
</exclusion>
5050
</exclusions>
5151
</dependency>
52+
<dependency>
53+
<groupId>com.microsoft.azure</groupId>
54+
<artifactId>TSS.Java</artifactId>
55+
<version>1.0.0</version>
56+
<scope>provided</scope>
57+
</dependency>
58+
<dependency>
59+
<groupId>org.bouncycastle</groupId>
60+
<!-- last version of 1.5 branch is bcprov-jdk15on 1.70 -->
61+
<artifactId>bcprov-jdk18on</artifactId>
62+
<version>1.76</version>
63+
</dependency>
5264
</dependencies>
5365

5466
<build>
67+
<plugins>
68+
<plugin>
69+
<groupId>org.apache.maven.plugins</groupId>
70+
<artifactId>maven-antrun-plugin</artifactId>
71+
<version>3.1.0</version>
72+
</plugin>
73+
</plugins>
5574
<pluginManagement>
5675
<plugins>
76+
<plugin>
77+
<groupId>org.apache.maven.plugins</groupId>
78+
<artifactId>maven-dependency-plugin</artifactId>
79+
<executions>
80+
<execution>
81+
<id>unpack-tss</id>
82+
<phase>generate-sources</phase>
83+
<goals>
84+
<goal>unpack</goal>
85+
</goals>
86+
<configuration>
87+
<echo>"Unpacking TSS.Java"</echo>
88+
<artifactItems>
89+
<artifactItem>
90+
<groupId>com.microsoft.azure</groupId>
91+
<artifactId>TSS.Java</artifactId>
92+
<version>1.0.0</version>
93+
<outputDirectory>
94+
${project.build.directory}/classes
95+
</outputDirectory>
96+
</artifactItem>
97+
</artifactItems>
98+
</configuration>
99+
</execution>
100+
</executions>
101+
</plugin>
102+
103+
<plugin>
104+
<groupId>org.apache.maven.plugins</groupId>
105+
<artifactId>maven-antrun-plugin</artifactId>
106+
<executions>
107+
108+
<execution>
109+
<!-- Remove classes from the root package and re jar -->
110+
<id>fix-tss</id>
111+
<phase>process-sources</phase>
112+
<goals>
113+
<goal>run</goal>
114+
</goals>
115+
<configuration>
116+
<target>
117+
<echo file="${project.build.outputDirectory}/deps.txt"
118+
message="compile classpath: ${compile_classpath}"/>
119+
<echo>"Fixing TSS.Java for OSGI"</echo>
120+
<delete>
121+
<fileset dir="${project.build.directory}/classes" includes="TSSMain.class"/>
122+
</delete>
123+
<jar destfile="${project.build.directory}/TSS.Java-fixed-1.0.0.jar">
124+
<fileset dir="${project.build.directory}/classes/tss"/>
125+
</jar>
126+
</target>
127+
</configuration>
128+
</execution>
129+
</executions>
130+
</plugin>
131+
132+
57133
<plugin>
58134
<groupId>biz.aQute.bnd</groupId>
59135
<artifactId>bnd-maven-plugin</artifactId>
@@ -67,6 +143,7 @@ Require-Capability:
67143
cardinality:=multiple
68144
SPI-Provider: tuwien.auto.calimero.serial.spi.SerialCom
69145
SPI-Consumer: java.util.ServiceLoader#load(java.lang.Class[tuwien.auto.calimero.serial.spi.SerialCom])
146+
-includeresource: "target/TSS.Java-fixed-1.0.0.jar";lib:=true
70147
]]>
71148
</bnd>
72149
</configuration>

bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/KNXBindingConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
public class KNXBindingConstants {
3333

3434
public static final String BINDING_ID = "knx";
35+
public static final String ENCYRPTED_PASSWORD_SERIALIZATION_PREFIX = "TpM2-pRoTeCteD-";
3536

3637
// Global config
3738
public static final String CONFIG_DISABLE_UOM = "disableUoM";

bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/AbstractKNXClient.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,32 @@ public AbstractKNXClient(int autoReconnectPeriod, ThingUID thingUID, int respons
152152
}
153153

154154
public void initialize() {
155+
/*
156+
* TpmInterface.SecuredPassword passKey = new TpmInterface.SecuredPassword("", "", "");
157+
* try {
158+
* TpmInterface tpmIf = new TpmInterface();
159+
* String tpmRev = tpmIf.getTpmVersion();
160+
* String tpmModel = "unknown";
161+
* try {
162+
* tpmModel = tpmIf.getTpmModel();
163+
* } catch (KNXException ignored) {
164+
* }
165+
* logger.info("TPM rev. {} detected, based on {}", tpmRev, tpmModel);
166+
*
167+
* passKey = tpmIf.encryptSecret("habOpen");
168+
* logger.warn("{}", passKey);
169+
* } catch (KNXException e) {
170+
* logger.warn("TPM exception", e);
171+
* }
172+
* try {
173+
* TpmInterface tpmIf = new TpmInterface();
174+
* String pass = tpmIf.decryptSecret(passKey);
175+
* logger.warn("TPM decoded: {}", pass);
176+
* } catch (KNXException e) {
177+
* logger.warn("TPM exception", e);
178+
* }
179+
*/
180+
155181
connect();
156182
}
157183

bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/config/BridgeConfiguration.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
package org.openhab.binding.knx.internal.config;
1414

1515
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
import org.eclipse.jdt.annotation.Nullable;
17+
import org.openhab.binding.knx.internal.KNXBindingConstants;
18+
import org.openhab.binding.knx.internal.tpm.TpmInterface;
19+
import org.openhab.core.auth.SecurityException;
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
1622

1723
/**
1824
* {@link org.openhab.binding.knx.internal.handler.KNXBridgeBaseThingHandler} configuration
@@ -22,6 +28,9 @@
2228
*/
2329
@NonNullByDefault
2430
public class BridgeConfiguration {
31+
private final Logger logger = LoggerFactory.getLogger(BridgeConfiguration.class);
32+
@Nullable
33+
TpmInterface tpmIf = null;
2534
private int autoReconnectPeriod = 0;
2635
private int readingPause = 0;
2736
private int readRetriesLimit = 0;
@@ -46,4 +55,27 @@ public int getResponseTimeout() {
4655
public void setAutoReconnectPeriod(int period) {
4756
autoReconnectPeriod = period;
4857
}
58+
59+
protected String decrypt(String secret) {
60+
if (secret.startsWith(KNXBindingConstants.ENCYRPTED_PASSWORD_SERIALIZATION_PREFIX)) {
61+
try {
62+
logger.info("trying to access TPM module");
63+
if (tpmIf == null) {
64+
tpmIf = new TpmInterface();
65+
logger.info("generating keys, this might take some time");
66+
}
67+
TpmInterface tmpTpmIf = tpmIf;
68+
if (tmpTpmIf != null) {
69+
secret = tmpTpmIf.deserializeAndDectryptSecret(
70+
secret.substring(KNXBindingConstants.ENCYRPTED_PASSWORD_SERIALIZATION_PREFIX.length()));
71+
} else {
72+
logger.error("Unable to decode stored password using TPM");
73+
}
74+
} catch (SecurityException e) {
75+
logger.error("Unable to decode stored password using TPM: {}", e.getMessage());
76+
// fall through
77+
}
78+
}
79+
return secret;
80+
}
4981
}

bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/config/IPBridgeConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ public String getTunnelUserId() {
6767
}
6868

6969
public String getTunnelUserPassword() {
70-
return tunnelUserPassword;
70+
return decrypt(tunnelUserPassword);
7171
}
7272

7373
public String getTunnelDeviceAuthentication() {
74-
return tunnelDeviceAuthentication;
74+
return decrypt(tunnelDeviceAuthentication);
7575
}
7676
}

bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/console/KNXCommandExtension.java

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import org.openhab.binding.knx.internal.KNXBindingConstants;
2121
import org.openhab.binding.knx.internal.factory.KNXHandlerFactory;
2222
import org.openhab.binding.knx.internal.handler.KNXBridgeBaseThingHandler;
23+
import org.openhab.binding.knx.internal.tpm.TpmInterface;
24+
import org.openhab.core.auth.SecurityException;
2325
import org.openhab.core.io.console.Console;
2426
import org.openhab.core.io.console.ConsoleCommandCompleter;
2527
import org.openhab.core.io.console.StringsCompleter;
@@ -39,7 +41,10 @@
3941
public class KNXCommandExtension extends AbstractConsoleCommandExtension implements ConsoleCommandCompleter {
4042

4143
private static final String CMD_LIST_UNKNOWN_GA = "list-unknown-ga";
42-
private static final StringsCompleter CMD_COMPLETER = new StringsCompleter(List.of(CMD_LIST_UNKNOWN_GA), false);
44+
private static final String CMD_TPM_INFO = "tpm-info";
45+
private static final String CMD_TPM_ENCRYPT = "tpm-encrypt";
46+
private static final StringsCompleter CMD_COMPLETER = new StringsCompleter(
47+
List.of(CMD_LIST_UNKNOWN_GA, CMD_TPM_INFO, CMD_TPM_ENCRYPT), false);
4348

4449
private final KNXHandlerFactory knxHandlerFactory;
4550

@@ -60,14 +65,47 @@ public void execute(String[] args, Console console) {
6065
}
6166
}
6267
return;
68+
} else if (args.length == 1 && CMD_TPM_INFO.equalsIgnoreCase(args[0])) {
69+
try {
70+
console.println("trying to access TPM module");
71+
TpmInterface tpm = new TpmInterface();
72+
console.println("TPM version: " + tpm.getTpmVersion());
73+
console.println("TPM model: " + tpm.getTpmModel());
74+
} catch (SecurityException e) {
75+
console.print("error: " + e.getMessage());
76+
}
77+
return;
78+
} else if (args.length == 2 && CMD_TPM_ENCRYPT.equalsIgnoreCase(args[0])) {
79+
try {
80+
console.println("trying to access TPM module");
81+
TpmInterface tpm = new TpmInterface();
82+
console.println("generating keys, this might take some time");
83+
String p = tpm.encryptAndSerializeSecret(args[1]);
84+
console.println("encrypted representation of password");
85+
console.println(KNXBindingConstants.ENCYRPTED_PASSWORD_SERIALIZATION_PREFIX + p);
86+
87+
// check if TPM can decrypt
88+
String decrypted = tpm.deserializeAndDectryptSecret(p);
89+
if (args[1].equals(decrypted)) {
90+
console.println("Password successfully recovered from encrypted representation");
91+
} else {
92+
console.println("WARNING: could not decrypt");
93+
}
94+
95+
} catch (SecurityException e) {
96+
console.print("error: " + e.getMessage());
97+
}
98+
return;
6399
}
64100
printUsage(console);
65101
}
66102

67103
@Override
68104
public List<String> getUsages() {
69-
return List
70-
.of(buildCommandUsage(CMD_LIST_UNKNOWN_GA, "list group addresses which are not configured in openHAB"));
105+
return List.of(
106+
buildCommandUsage(CMD_LIST_UNKNOWN_GA, "list group addresses which are not configured in openHAB"),
107+
buildCommandUsage(CMD_TPM_ENCRYPT + " <password>", "Encrypt a password"),
108+
buildCommandUsage(CMD_TPM_INFO, "Get information about available TPM"));
71109
}
72110

73111
@Override

0 commit comments

Comments
 (0)