Skip to content

Commit

Permalink
[knx] Add support for using hardware TPM modules
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
holgerfriedrich committed Jul 31, 2023
1 parent f6e750a commit d5b0877
Show file tree
Hide file tree
Showing 8 changed files with 575 additions and 5 deletions.
76 changes: 76 additions & 0 deletions bundles/org.openhab.binding.knx/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,86 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>TSS.Java</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-tss</id>
<phase>generate-sources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<echo>"Unpacking TSS.Java"</echo>
<artifactItems>
<artifactItem>
<groupId>com.microsoft.azure</groupId>
<artifactId>TSS.Java</artifactId>
<version>1.0.0</version>
<outputDirectory>
${project.build.directory}/classes
</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>

<execution>
<!-- Remove classes from the root package and re jar -->
<id>fix-tss</id>
<phase>process-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<echo file="${project.build.outputDirectory}/deps.txt"
message="compile classpath: ${compile_classpath}"/>
<echo>"Fixing TSS.Java for OSGI"</echo>
<delete>
<fileset dir="${project.build.directory}/classes" includes="TSSMain.class"/>
</delete>
<jar destfile="${project.build.directory}/TSS.Java-fixed-1.0.0.jar">
<fileset dir="${project.build.directory}/classes/tss"/>
</jar>
</target>
</configuration>
</execution>
</executions>
</plugin>


<plugin>
<groupId>biz.aQute.bnd</groupId>
<artifactId>bnd-maven-plugin</artifactId>
Expand All @@ -67,6 +142,7 @@ Require-Capability:
cardinality:=multiple
SPI-Provider: tuwien.auto.calimero.serial.spi.SerialCom
SPI-Consumer: java.util.ServiceLoader#load(java.lang.Class[tuwien.auto.calimero.serial.spi.SerialCom])
-includeresource: "target/TSS.Java-fixed-1.0.0.jar";lib:=true
]]>
</bnd>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
public class KNXBindingConstants {

public static final String BINDING_ID = "knx";
public static final String ENCYRPTED_PASSWORD_SERIALIZATION_PREFIX = "TpM2-pRoTeCteD-";

// Global config
public static final String CONFIG_DISABLE_UOM = "disableUoM";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,32 @@ public AbstractKNXClient(int autoReconnectPeriod, ThingUID thingUID, int respons
}

public void initialize() {
/*
* TpmInterface.SecuredPassword passKey = new TpmInterface.SecuredPassword("", "", "");
* try {
* TpmInterface tpmIf = new TpmInterface();
* String tpmRev = tpmIf.getTpmVersion();
* String tpmModel = "unknown";
* try {
* tpmModel = tpmIf.getTpmModel();
* } catch (KNXException ignored) {
* }
* logger.info("TPM rev. {} detected, based on {}", tpmRev, tpmModel);
*
* passKey = tpmIf.encryptSecret("habOpen");
* logger.warn("{}", passKey);
* } catch (KNXException e) {
* logger.warn("TPM exception", e);
* }
* try {
* TpmInterface tpmIf = new TpmInterface();
* String pass = tpmIf.decryptSecret(passKey);
* logger.warn("TPM decoded: {}", pass);
* } catch (KNXException e) {
* logger.warn("TPM exception", e);
* }
*/

connect();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
package org.openhab.binding.knx.internal.config;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.knx.internal.KNXBindingConstants;
import org.openhab.binding.knx.internal.tpm.TpmInterface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import tuwien.auto.calimero.KNXException;

/**
* {@link org.openhab.binding.knx.internal.handler.KNXBridgeBaseThingHandler} configuration
Expand All @@ -22,6 +29,9 @@
*/
@NonNullByDefault
public class BridgeConfiguration {
private final Logger logger = LoggerFactory.getLogger(BridgeConfiguration.class);
@Nullable
TpmInterface tpmIf = null;
private int autoReconnectPeriod = 0;
private int readingPause = 0;
private int readRetriesLimit = 0;
Expand All @@ -46,4 +56,27 @@ public int getResponseTimeout() {
public void setAutoReconnectPeriod(int period) {
autoReconnectPeriod = period;
}

protected String decrypt(String secret) {
if (secret.startsWith(KNXBindingConstants.ENCYRPTED_PASSWORD_SERIALIZATION_PREFIX)) {
try {
logger.info("trying to access TPM module");
if (tpmIf == null) {
tpmIf = new TpmInterface();
logger.info("generating keys, this might take some time");
}
TpmInterface tmpTpmIf = tpmIf;
if (tmpTpmIf != null) {
secret = tmpTpmIf.deserializeAndDectryptSecret(
secret.substring(KNXBindingConstants.ENCYRPTED_PASSWORD_SERIALIZATION_PREFIX.length()));
} else {
logger.error("Unable to decode stored password using TPM");
}
} catch (KNXException e) {
logger.error("Unable to decode stored password using TPM: {}", e.getMessage());
// fall through
}
}
return secret;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ public String getTunnelUserId() {
}

public String getTunnelUserPassword() {
return tunnelUserPassword;
return decrypt(tunnelUserPassword);
}

public String getTunnelDeviceAuthentication() {
return tunnelDeviceAuthentication;
return decrypt(tunnelDeviceAuthentication);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.openhab.binding.knx.internal.KNXBindingConstants;
import org.openhab.binding.knx.internal.factory.KNXHandlerFactory;
import org.openhab.binding.knx.internal.handler.KNXBridgeBaseThingHandler;
import org.openhab.binding.knx.internal.tpm.TpmInterface;
import org.openhab.core.io.console.Console;
import org.openhab.core.io.console.ConsoleCommandCompleter;
import org.openhab.core.io.console.StringsCompleter;
Expand All @@ -29,6 +30,8 @@
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import tuwien.auto.calimero.KNXException;

/**
* The {@link KNXCommandExtension} is responsible for handling console commands
*
Expand All @@ -39,7 +42,10 @@
public class KNXCommandExtension extends AbstractConsoleCommandExtension implements ConsoleCommandCompleter {

private static final String CMD_LIST_UNKNOWN_GA = "list-unknown-ga";
private static final StringsCompleter CMD_COMPLETER = new StringsCompleter(List.of(CMD_LIST_UNKNOWN_GA), false);
private static final String CMD_TPM_INFO = "tpm-info";
private static final String CMD_TPM_ENCRYPT = "tpm-encrypt";
private static final StringsCompleter CMD_COMPLETER = new StringsCompleter(
List.of(CMD_LIST_UNKNOWN_GA, CMD_TPM_INFO, CMD_TPM_ENCRYPT), false);

private final KNXHandlerFactory knxHandlerFactory;

Expand All @@ -60,14 +66,47 @@ public void execute(String[] args, Console console) {
}
}
return;
} else if (args.length == 1 && CMD_TPM_INFO.equalsIgnoreCase(args[0])) {
try {
console.println("trying to access TPM module");
TpmInterface tpm = new TpmInterface();
console.println("TPM version: " + tpm.getTpmVersion());
console.println("TPM model: " + tpm.getTpmModel());
} catch (KNXException e) {
console.print("error: " + e.getMessage());
}
return;
} else if (args.length == 2 && CMD_TPM_ENCRYPT.equalsIgnoreCase(args[0])) {
try {
console.println("trying to access TPM module");
TpmInterface tpm = new TpmInterface();
console.println("generating keys, this might take some time");
String p = tpm.encryptAndSerializeSecret(args[1]);
console.println("encrypted representation of password");
console.println(KNXBindingConstants.ENCYRPTED_PASSWORD_SERIALIZATION_PREFIX + p);

// check if TPM can decrypt
String decrypted = tpm.deserializeAndDectryptSecret(p);
if (args[1].equals(decrypted)) {
console.println("Password successfully recovered from encrypted representation");
} else {
console.println("WARNING: could not decrypt");
}

} catch (KNXException e) {
console.print("error: " + e.getMessage());
}
return;
}
printUsage(console);
}

@Override
public List<String> getUsages() {
return List
.of(buildCommandUsage(CMD_LIST_UNKNOWN_GA, "list group addresses which are not configured in openHAB"));
return List.of(
buildCommandUsage(CMD_LIST_UNKNOWN_GA, "list group addresses which are not configured in openHAB"),
buildCommandUsage(CMD_TPM_ENCRYPT + " <password>", "Encrypt a password"),
buildCommandUsage(CMD_TPM_INFO, "Get information about available TPM"));
}

@Override
Expand Down
Loading

0 comments on commit d5b0877

Please sign in to comment.