diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java
index b4ac3d30fd..fcf68bf13a 100644
--- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java
+++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java
@@ -22,28 +22,11 @@ import org.eclipse.leshan.core.util.Hex;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
-import java.math.BigInteger;
-import java.security.AlgorithmParameters;
-import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509Certificate;
-import java.security.spec.ECGenParameterSpec;
-import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
-import java.security.spec.ECPublicKeySpec;
-import java.security.spec.KeySpec;
-
@Slf4j
@Service
@RequiredArgsConstructor
@@ -72,10 +55,9 @@ public class LwM2MServerSecurityInfoRepository {
private String getPublicKey(LwM2MSecureServerConfig config) {
try {
- KeyStore keyStore = serverConfig.getKeyStoreValue();
- if (keyStore != null) {
- X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(config.getCertificateAlias());
- return Hex.encodeHexString(serverCertificate.getPublicKey().getEncoded());
+ SslCredentials sslCredentials = config.getSslCredentials();
+ if (sslCredentials != null) {
+ return Hex.encodeHexString(sslCredentials.getPublicKey().getEncoded());
}
} catch (Exception e) {
log.trace("Failed to fetch public key from key store!", e);
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index 57a6a638af..f88d5f297c 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -619,14 +619,28 @@ transport:
bind_port: "${MQTT_SSL_BIND_PORT:8883}"
# SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext
protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}"
- # Path to the key store that holds the SSL certificate
- key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
- # Password used to access the key store
- key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
- # Password used to access the key
- key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
- # Type of the key store
- key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
+ # Server SSL credentials
+ credentials:
+ # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
+ type: "${MQTT_SSL_CREDENTIALS_TYPE:PEM}"
+ # PEM server credentials
+ pem:
+ # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
+ cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}"
+ # Path to the server certificate private key file (optional)
+ key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}"
+ # Server certificate private key password (optional)
+ key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}"
+ # Keystore server credentials
+ keystore:
+ # Type of the key store
+ type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the SSL certificate
+ store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
+ # Password used to access the key store
+ store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
+ # Password used to access the key
+ key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
# Skip certificate validity check for client certificates.
skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
# Local CoAP transport parameters
@@ -645,14 +659,30 @@ transport:
bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}"
# CoAP DTLS bind port
bind_port: "${COAP_DTLS_BIND_PORT:5684}"
- # Path to the key store that holds the certificate
- key_store: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
- # Password used to access the key store
- key_store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
- # Password used to access the key
- key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
- # Key alias
- key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
+ # Server DTLS credentials
+ credentials:
+ # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
+ type: "${COAP_DTLS_CREDENTIALS_TYPE:PEM}"
+ # PEM server credentials
+ pem:
+ # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
+ cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}"
+ # Path to the server certificate private key file (optional)
+ key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}"
+ # Server certificate private key password (optional)
+ key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}"
+ # Keystore server credentials
+ keystore:
+ # Type of the key store
+ type: "${COAP_DTLS_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the SSL certificate
+ store_file: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
+ # Password used to access the key store
+ store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
+ # Password used to access the key
+ key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
+ # Key alias
+ key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
x509:
# Skip certificate validity check for client certificates.
skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
@@ -669,9 +699,33 @@ transport:
security:
bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}"
bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}"
+ # Server X509 Certificates support
+ credentials:
+ # Whether to enable LWM2M server X509 Certificate/RPK support
+ enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}"
+ # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
+ type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}"
+ # PEM server credentials
+ pem:
+ # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
+ cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}"
+ # Path to the server certificate private key file (optional)
+ key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}"
+ # Server certificate private key password (optional)
+ key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}"
+ # Keystore server credentials
+ keystore:
+ # Type of the key store
+ type: "${LWM2M_SERVER_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the SSL certificate
+ store_file: "${LWM2M_SERVER_KEY_STORE:lwm2mserver.jks}"
+ # Password used to access the key store
+ store_password: "${LWM2M_SERVER_KEY_STORE_PASSWORD:server_ks_password}"
+ # Password used to access the key
+ key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_key_password}"
+ # Key alias
+ key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
# Only Certificate_x509:
- key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
- key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}"
skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
bootstrap:
enable: "${LWM2M_ENABLED_BS:true}"
@@ -681,18 +735,51 @@ transport:
security:
bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}"
bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}"
- # Only Certificate_x509:
- key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
- key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}"
+ # Bootstrap server X509 Certificates support
+ credentials:
+ # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support
+ enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}"
+ # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
+ type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}"
+ # PEM server credentials
+ pem:
+ # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
+ cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}"
+ # Path to the server certificate private key file (optional)
+ key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}"
+ # Server certificate private key password (optional)
+ key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}"
+ # Keystore server credentials
+ keystore:
+ # Type of the key store
+ type: "${LWM2M_BS_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the SSL certificate
+ store_file: "${LWM2M_BS_KEY_STORE:lwm2mserver.jks}"
+ # Password used to access the key store
+ store_password: "${LWM2M_BS_KEY_STORE_PASSWORD:server_ks_password}"
+ # Password used to access the key
+ key_password: "${LWM2M_BS_KEY_PASSWORD:server_key_password}"
+ # Key alias
+ key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
security:
- # Certificate_x509:
- # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
- # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
- key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
- # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks"
- key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}"
- key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}"
- root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}"
+ # X509 trust certificates
+ trust-credentials:
+ # Whether to load X509 trust certificates
+ enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}"
+ # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore)
+ type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}"
+ # PEM certificates
+ pem:
+ # Path to the certificates file (holds trust certificates)
+ cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mserver.pem}"
+ # Keystore with trust certificates
+ keystore:
+ # Type of the key store
+ type: "${LWM2M_TRUST_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the X509 certificates
+ store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mserver.jks}"
+ # Password used to access the key store
+ store_password: "${LWM2M_TRUST_KEY_STORE_PASSWORD:server_ks_password}"
recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
timeout: "${LWM2M_TIMEOUT:120000}"
diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java
index f433909242..6f82c79041 100644
--- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java
+++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java
@@ -20,11 +20,16 @@ import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.ResourceUtils;
import org.thingsboard.server.common.transport.TransportService;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import java.io.IOException;
@@ -45,17 +50,15 @@ public class TbCoapDtlsSettings {
@Value("${transport.coap.dtls.bind_port}")
private Integer port;
- @Value("${transport.coap.dtls.key_store}")
- private String keyStoreFile;
-
- @Value("${transport.coap.dtls.key_store_password}")
- private String keyStorePassword;
-
- @Value("${transport.coap.dtls.key_password}")
- private String keyPassword;
+ @Bean
+ @ConfigurationProperties(prefix = "transport.coap.dtls.credentials")
+ public SslCredentialsConfig coapDtlsCredentials() {
+ return new SslCredentialsConfig("COAP DTLS Credentials", false);
+ }
- @Value("${transport.coap.dtls.key_alias}")
- private String keyAlias;
+ @Autowired
+ @Qualifier("coapDtlsCredentials")
+ private SslCredentialsConfig coapDtlsCredentialsConfig;
@Value("${transport.coap.dtls.x509.skip_validity_check_for_client_cert:false}")
private boolean skipValidityCheckForClientCert;
@@ -75,8 +78,9 @@ public class TbCoapDtlsSettings {
public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException {
DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder();
configBuilder.setAddress(getInetSocketAddress());
- String keyStoreFilePath = ResourceUtils.getUri(this, keyStoreFile);
- SslContextUtil.Credentials serverCredentials = loadServerCredentials(keyStoreFilePath);
+ SslCredentials sslCredentials = this.coapDtlsCredentialsConfig.getCredentials();
+ SslContextUtil.Credentials serverCredentials =
+ new SslContextUtil.Credentials(sslCredentials.getPrivateKey(), null, sslCredentials.getCertificateChain());
configBuilder.setServerOnly(true);
configBuilder.setClientAuthenticationRequired(false);
configBuilder.setClientAuthenticationWanted(true);
@@ -94,15 +98,6 @@ public class TbCoapDtlsSettings {
return configBuilder.build();
}
- private SslContextUtil.Credentials loadServerCredentials(String keyStoreFilePath) {
- try {
- return SslContextUtil.loadCredentials(keyStoreFilePath, keyAlias, keyStorePassword.toCharArray(),
- keyPassword.toCharArray());
- } catch (GeneralSecurityException | IOException e) {
- throw new RuntimeException("Failed to load serverCredentials due to: ", e);
- }
- }
-
private InetSocketAddress getInetSocketAddress() throws UnknownHostException {
InetAddress addr = InetAddress.getByName(host);
return new InetSocketAddress(addr, port);
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java
index 754476bc26..b354b98bdb 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/ResourceUtils.java
@@ -27,6 +27,30 @@ import java.net.URL;
@Slf4j
public class ResourceUtils {
+ public static boolean resourceExists(Object classLoaderSource, String filePath) {
+ return resourceExists(classLoaderSource.getClass().getClassLoader(), filePath);
+ }
+
+ public static boolean resourceExists(ClassLoader classLoader, String filePath) {
+ File resourceFile = new File(filePath);
+ if (resourceFile.exists()) {
+ return true;
+ } else {
+ InputStream classPathStream = classLoader.getResourceAsStream(filePath);
+ if (classPathStream != null) {
+ return true;
+ } else {
+ try {
+ URL url = Resources.getResource(filePath);
+ if (url != null) {
+ return true;
+ }
+ } catch (IllegalArgumentException e) {}
+ }
+ }
+ return false;
+ }
+
public static InputStream getInputStream(Object classLoaderSource, String filePath) {
return getInputStream(classLoaderSource.getClass().getClassLoader(), filePath);
}
diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java
index 16f9443547..0ea9be4388 100644
--- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java
+++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java
@@ -27,6 +27,7 @@ import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore;
import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore;
import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigurationAdapter;
@@ -114,49 +115,22 @@ public class LwM2MTransportBootstrapService {
}
private void setServerWithCredentials(LeshanBootstrapServerBuilder builder) {
- try {
- if (serverConfig.getKeyStoreValue() != null) {
- KeyStore keyStoreServer = serverConfig.getKeyStoreValue();
- if (this.setBuilderX509(builder)) {
- X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(serverConfig.getRootCertificateAlias());
- if (rootCAX509Cert != null) {
- X509Certificate[] trustedCertificates = new X509Certificate[1];
- trustedCertificates[0] = rootCAX509Cert;
- builder.setTrustedCertificates(trustedCertificates);
- } else {
- /* by default trust all */
- builder.setTrustedCertificates(new X509Certificate[0]);
- }
- }
+ if (this.bootstrapConfig.getSslCredentials() != null) {
+ SslCredentials sslCredentials = this.bootstrapConfig.getSslCredentials();
+ builder.setPublicKey(sslCredentials.getPublicKey());
+ builder.setPrivateKey(sslCredentials.getPrivateKey());
+ builder.setCertificateChain(sslCredentials.getCertificateChain());
+ if (this.serverConfig.getTrustSslCredentials() != null) {
+ builder.setTrustedCertificates(this.serverConfig.getTrustSslCredentials().getTrustedCertificates());
} else {
/* by default trust all */
builder.setTrustedCertificates(new X509Certificate[0]);
- log.info("Unable to load X509 files for BootStrapServer");
- this.pskMode = true;
}
- } catch (KeyStoreException ex) {
- log.error("[{}] Unable to load X509 files server", ex.getMessage());
+ } else {
+ /* by default trust all */
+ builder.setTrustedCertificates(new X509Certificate[0]);
+ log.info("Unable to load X509 files for BootStrapServer");
+ this.pskMode = true;
}
}
-
- private boolean setBuilderX509(LeshanBootstrapServerBuilder builder) {
- try {
- X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(serverConfig.getKeyStoreValue().getCertificateChain(this.bootstrapConfig.getCertificateAlias()));
- X509Certificate serverCertificate = certificateChain[0];
- PrivateKey privateKey = (PrivateKey) serverConfig.getKeyStoreValue().getKey(this.bootstrapConfig.getCertificateAlias(), serverConfig.getCertificatePassword() == null ? null : serverConfig.getCertificatePassword().toCharArray());
- PublicKey publicKey = serverCertificate.getPublicKey();
- if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) {
- builder.setPublicKey(serverCertificate.getPublicKey());
- builder.setPrivateKey(privateKey);
- builder.setCertificateChain(certificateChain);
- return true;
- } else {
- return false;
- }
- } catch (Exception ex) {
- log.error("[{}] Unable to load KeyStore files server", ex.getMessage());
- return false;
- }
- }
-
}
diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MSecureServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MSecureServerConfig.java
index a525c5f157..b8a4f2c976 100644
--- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MSecureServerConfig.java
+++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MSecureServerConfig.java
@@ -15,6 +15,8 @@
*/
package org.thingsboard.server.transport.lwm2m.config;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
+
public interface LwM2MSecureServerConfig {
Integer getId();
@@ -27,8 +29,6 @@ public interface LwM2MSecureServerConfig {
Integer getSecurePort();
- String getCertificateAlias();
-
- String getCertificatePassword();
+ SslCredentials getSslCredentials();
}
diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java
index 0806ef9e90..749f7352ba 100644
--- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java
+++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java
@@ -17,9 +17,15 @@ package org.thingsboard.server.transport.lwm2m.config;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
@Slf4j
@Component
@@ -46,12 +52,18 @@ public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig {
@Value("${transport.lwm2m.bootstrap.security.bind_port:}")
private Integer securePort;
- @Getter
- @Value("${transport.lwm2m.bootstrap.security.key_alias:}")
- private String certificateAlias;
+ @Bean
+ @ConfigurationProperties(prefix = "transport.lwm2m.bootstrap.security.credentials")
+ public SslCredentialsConfig lwm2mBootstrapCredentials() {
+ return new SslCredentialsConfig("LWM2M Bootstrap DTLS Credentials", false);
+ }
- @Getter
- @Value("${transport.lwm2m.bootstrap.security.key_password:}")
- private String certificatePassword;
+ @Autowired
+ @Qualifier("lwm2mBootstrapCredentials")
+ private SslCredentialsConfig credentialsConfig;
+ @Override
+ public SslCredentials getSslCredentials() {
+ return this.credentialsConfig.getCredentials();
+ }
}
diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java
index bde8741f3b..f444b74c2b 100644
--- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java
+++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java
@@ -18,10 +18,16 @@ package org.thingsboard.server.transport.lwm2m.config;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.ResourceUtils;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
import javax.annotation.PostConstruct;
import java.io.InputStream;
@@ -64,26 +70,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
@Value("${transport.lwm2m.clean_period_in_sec:}")
private int cleanPeriodInSec;
- @Getter
- @Value("${transport.lwm2m.security.key_store_type:}")
- private String keyStoreType;
-
- @Getter
- @Value("${transport.lwm2m.security.key_store:}")
- private String keyStoreFilePath;
-
- @Getter
- @Setter
- private KeyStore keyStoreValue;
-
- @Getter
- @Value("${transport.lwm2m.security.key_store_password:}")
- private String keyStorePassword;
-
- @Getter
- @Value("${transport.lwm2m.security.root_alias:}")
- private String rootCertificateAlias;
-
@Getter
@Value("${transport.lwm2m.server.id:}")
private Integer id;
@@ -104,14 +90,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
@Value("${transport.lwm2m.server.security.bind_port:}")
private Integer securePort;
- @Getter
- @Value("${transport.lwm2m.server.security.key_alias:}")
- private String certificateAlias;
-
- @Getter
- @Value("${transport.lwm2m.server.security.key_password:}")
- private String certificatePassword;
-
@Getter
@Value("${transport.lwm2m.log_max_length:}")
private int logMaxLength;
@@ -124,15 +102,32 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
@Value("${transport.lwm2m.paging_transmission_window:10000}")
private long pagingTransmissionWindow;
- @PostConstruct
- public void init() {
- try {
- InputStream keyStoreInputStream = ResourceUtils.getInputStream(this, keyStoreFilePath);
- keyStoreValue = KeyStore.getInstance(keyStoreType);
- keyStoreValue.load(keyStoreInputStream, keyStorePassword == null ? null : keyStorePassword.toCharArray());
- } catch (Exception e) {
- log.info("Unable to lookup LwM2M keystore. Reason: {}, {}", keyStoreFilePath, e.getMessage());
- }
+ @Bean
+ @ConfigurationProperties(prefix = "transport.lwm2m.server.security.credentials")
+ public SslCredentialsConfig lwm2mServerCredentials() {
+ return new SslCredentialsConfig("LWM2M Server DTLS Credentials", false);
+ }
+
+ @Autowired
+ @Qualifier("lwm2mServerCredentials")
+ private SslCredentialsConfig credentialsConfig;
+
+ @Bean
+ @ConfigurationProperties(prefix = "transport.lwm2m.security.trust-credentials")
+ public SslCredentialsConfig lwm2mTrustCredentials() {
+ return new SslCredentialsConfig("LWM2M Trust Credentials", true);
}
+ @Autowired
+ @Qualifier("lwm2mTrustCredentials")
+ private SslCredentialsConfig trustCredentialsConfig;
+
+ @Override
+ public SslCredentials getSslCredentials() {
+ return this.credentialsConfig.getCredentials();
+ }
+
+ public SslCredentials getTrustSslCredentials() {
+ return this.trustCredentialsConfig.getCredentials();
+ }
}
diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java
index fe04410c17..1837093e8c 100644
--- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java
+++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java
@@ -87,12 +87,8 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
try {
/* by default trust all */
X509Certificate[] trustedCertificates = new X509Certificate[0];
- if (config.getKeyStoreValue() != null) {
- X509Certificate rootCAX509Cert = (X509Certificate) config.getKeyStoreValue().getCertificate(config.getRootCertificateAlias());
- if (rootCAX509Cert != null) {
- trustedCertificates = new X509Certificate[1];
- trustedCertificates[0] = rootCAX509Cert;
- }
+ if (config.getTrustSslCredentials() != null) {
+ trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates();
}
staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates);
} catch (Exception e) {
diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java
index 5a02f3b194..3efc71b5fe 100644
--- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java
+++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java
@@ -29,6 +29,7 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider;
import org.springframework.stereotype.Component;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer;
@@ -141,7 +142,11 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
}
private void setServerWithCredentials(LeshanServerBuilder builder, DtlsConnectorConfig.Builder dtlsConfig) {
- if (config.getKeyStoreValue() != null && this.setBuilderX509(builder)) {
+ if (this.config.getSslCredentials() != null) {
+ SslCredentials sslCredentials = this.config.getSslCredentials();
+ builder.setPublicKey(sslCredentials.getPublicKey());
+ builder.setPrivateKey(sslCredentials.getPrivateKey());
+ builder.setCertificateChain(sslCredentials.getCertificateChain());
dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier);
builder.setAuthorizer(authorizer);
dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES);
@@ -153,26 +158,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
}
}
- private boolean setBuilderX509(LeshanServerBuilder builder) {
- try {
- X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(config.getKeyStoreValue().getCertificateChain(config.getCertificateAlias()));
- X509Certificate serverCertificate = certificateChain[0];
- PrivateKey privateKey = (PrivateKey) config.getKeyStoreValue().getKey(config.getCertificateAlias(), config.getCertificatePassword() == null ? null : config.getCertificatePassword().toCharArray());
- PublicKey publicKey = serverCertificate.getPublicKey();
- if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) {
- builder.setPublicKey(serverCertificate.getPublicKey());
- builder.setPrivateKey(privateKey);
- builder.setCertificateChain(certificateChain);
- return true;
- } else {
- return false;
- }
- } catch (Exception ex) {
- log.error("[{}] Unable to load KeyStore files server", ex.getMessage());
- return false;
- }
- }
-
@Override
public String getName() {
return DataConstants.LWM2M_TRANSPORT_NAME;
diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java
index fad743aec2..215aef408c 100644
--- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java
+++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java
@@ -18,16 +18,20 @@ package org.thingsboard.server.transport.mqtt;
import io.netty.handler.ssl.SslHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.DeviceTransportType;
-import org.thingsboard.server.common.data.ResourceUtils;
import org.thingsboard.server.common.msg.EncryptionUtil;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
+import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
import org.thingsboard.server.common.transport.util.SslUtil;
import org.thingsboard.server.gen.transport.TransportProtos;
@@ -38,8 +42,6 @@ import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
-import java.io.InputStream;
-import java.security.KeyStore;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
@@ -56,18 +58,20 @@ public class MqttSslHandlerProvider {
@Value("${transport.mqtt.ssl.protocol}")
private String sslProtocol;
- @Value("${transport.mqtt.ssl.key_store}")
- private String keyStoreFile;
- @Value("${transport.mqtt.ssl.key_store_password}")
- private String keyStorePassword;
- @Value("${transport.mqtt.ssl.key_password}")
- private String keyPassword;
- @Value("${transport.mqtt.ssl.key_store_type}")
- private String keyStoreType;
@Autowired
private TransportService transportService;
+ @Bean
+ @ConfigurationProperties(prefix = "transport.mqtt.ssl.credentials")
+ public SslCredentialsConfig mqttSslCredentials() {
+ return new SslCredentialsConfig("MQTT SSL Credentials", false);
+ }
+
+ @Autowired
+ @Qualifier("mqttSslCredentials")
+ private SslCredentialsConfig mqttSslCredentialsConfig;
+
private SSLContext sslContext;
public SslHandler getSslHandler() {
@@ -86,19 +90,9 @@ public class MqttSslHandlerProvider {
private SSLContext createSslContext() {
try {
- TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- KeyStore trustStore = KeyStore.getInstance(keyStoreType);
- try (InputStream tsFileInputStream = ResourceUtils.getInputStream(this, keyStoreFile)) {
- trustStore.load(tsFileInputStream, keyStorePassword.toCharArray());
- }
- tmFactory.init(trustStore);
-
- KeyStore ks = KeyStore.getInstance(keyStoreType);
- try (InputStream ksFileInputStream = ResourceUtils.getInputStream(this, keyStoreFile)) {
- ks.load(ksFileInputStream, keyStorePassword.toCharArray());
- }
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- kmf.init(ks, keyPassword.toCharArray());
+ SslCredentials sslCredentials = this.mqttSslCredentialsConfig.getCredentials();
+ TrustManagerFactory tmFactory = sslCredentials.createTrustManagerFactory();
+ KeyManagerFactory kmf = sslCredentials.createKeyManagerFactory();
KeyManager[] km = kmf.getKeyManagers();
TrustManager x509wrapped = getX509TrustManager(tmFactory);
diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml
index fad019a1b5..b66676e61c 100644
--- a/common/transport/transport-api/pom.xml
+++ b/common/transport/transport-api/pom.xml
@@ -129,6 +129,14 @@
org.eclipse.leshan
leshan-server-cf
+
+ org.bouncycastle
+ bcprov-jdk15on
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+
diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java
new file mode 100644
index 0000000000..04dafc56fd
--- /dev/null
+++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java
@@ -0,0 +1,191 @@
+/**
+ * Copyright © 2016-2021 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.common.transport.config.ssl;
+
+import org.thingsboard.server.common.data.StringUtils;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableEntryException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+public abstract class AbstractSslCredentials implements SslCredentials {
+
+ private char[] keyPasswordArray;
+
+ private KeyStore keyStore;
+
+ private PrivateKey privateKey;
+
+ private PublicKey publicKey;
+
+ private X509Certificate[] chain;
+
+ private X509Certificate[] trusts;
+
+ @Override
+ public void init(boolean trustsOnly) throws IOException, GeneralSecurityException {
+ String keyPassword = getKeyPassword();
+ if (StringUtils.isEmpty(keyPassword)) {
+ this.keyPasswordArray = new char[0];
+ } else {
+ this.keyPasswordArray = keyPassword.toCharArray();
+ }
+ this.keyStore = this.loadKeyStore(trustsOnly, this.keyPasswordArray);
+ Set trustedCerts = getTrustedCerts(this.keyStore);
+ this.trusts = trustedCerts.toArray(new X509Certificate[0]);
+ if (!trustsOnly) {
+ PrivateKeyEntry privateKeyEntry = null;
+ String keyAlias = this.getKeyAlias();
+ if (!StringUtils.isEmpty(keyAlias)) {
+ privateKeyEntry = tryGetPrivateKeyEntry(this.keyStore, keyAlias, this.keyPasswordArray);
+ } else {
+ for (Enumeration e = this.keyStore.aliases(); e.hasMoreElements(); ) {
+ String alias = e.nextElement();
+ privateKeyEntry = tryGetPrivateKeyEntry(this.keyStore, alias, this.keyPasswordArray);
+ if (privateKeyEntry != null) {
+ break;
+ }
+ }
+ }
+ if (privateKeyEntry == null) {
+ throw new IllegalArgumentException("Failed to get private key from the keystore or pem files. " +
+ "Please check if the private key exists in the keystore or pem files and if the provided private key password is valid.");
+ }
+ this.chain = asX509Certificates(privateKeyEntry.getCertificateChain());
+ this.privateKey = privateKeyEntry.getPrivateKey();
+ if (this.chain.length > 0) {
+ this.publicKey = this.chain[0].getPublicKey();
+ }
+ }
+ }
+
+ @Override
+ public PrivateKey getPrivateKey() {
+ return this.privateKey;
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ return this.publicKey;
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain() {
+ return this.chain;
+ }
+
+ @Override
+ public X509Certificate[] getTrustedCertificates() {
+ return this.trusts;
+ }
+
+ @Override
+ public TrustManagerFactory createTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException {
+ TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmFactory.init(this.keyStore);
+ return tmFactory;
+ }
+
+ @Override
+ public KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(this.keyStore, this.keyPasswordArray);
+ return kmf;
+ }
+
+ protected abstract boolean canUse();
+
+ protected abstract String getKeyPassword();
+
+ protected abstract String getKeyAlias();
+
+ protected abstract KeyStore loadKeyStore(boolean isPrivateKeyRequired, char[] keyPasswordArray) throws IOException, GeneralSecurityException;
+
+ private static X509Certificate[] asX509Certificates(Certificate[] certificates) {
+ if (null == certificates || 0 == certificates.length) {
+ throw new IllegalArgumentException("certificates missing!");
+ }
+ X509Certificate[] x509Certificates = new X509Certificate[certificates.length];
+ for (int index = 0; certificates.length > index; ++index) {
+ if (null == certificates[index]) {
+ throw new IllegalArgumentException("[" + index + "] is null!");
+ }
+ try {
+ x509Certificates[index] = (X509Certificate) certificates[index];
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("[" + index + "] is not a x509 certificate! Instead it's a "
+ + certificates[index].getClass().getName());
+ }
+ }
+ return x509Certificates;
+ }
+
+ private static PrivateKeyEntry tryGetPrivateKeyEntry(KeyStore keyStore, String alias, char[] pwd) {
+ PrivateKeyEntry entry = null;
+ try {
+ if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
+ try {
+ entry = (KeyStore.PrivateKeyEntry) keyStore
+ .getEntry(alias, new KeyStore.PasswordProtection(pwd));
+ } catch (UnsupportedOperationException e) {
+ PrivateKey key = (PrivateKey) keyStore.getKey(alias, pwd);
+ Certificate[] certs = keyStore.getCertificateChain(alias);
+ entry = new KeyStore.PrivateKeyEntry(key, certs);
+ }
+ }
+ } catch (KeyStoreException | UnrecoverableEntryException | NoSuchAlgorithmException ignored) {}
+ return entry;
+ }
+
+ private static Set getTrustedCerts(KeyStore ks) {
+ Set set = new HashSet<>();
+ try {
+ for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) {
+ String alias = e.nextElement();
+ if (ks.isCertificateEntry(alias)) {
+ Certificate cert = ks.getCertificate(alias);
+ if (cert instanceof X509Certificate) {
+ set.add((X509Certificate)cert);
+ }
+ } else if (ks.isKeyEntry(alias)) {
+ Certificate[] certs = ks.getCertificateChain(alias);
+ if ((certs != null) && (certs.length > 0) &&
+ (certs[0] instanceof X509Certificate)) {
+ set.add((X509Certificate)certs[0]);
+ }
+ }
+ }
+ } catch (KeyStoreException ignored) {}
+ return Collections.unmodifiableSet(set);
+ }
+
+
+}
diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/KeystoreSslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/KeystoreSslCredentials.java
new file mode 100644
index 0000000000..56f4009b0d
--- /dev/null
+++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/KeystoreSslCredentials.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright © 2016-2021 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.common.transport.config.ssl;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.thingsboard.server.common.data.ResourceUtils;
+import org.thingsboard.server.common.data.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class KeystoreSslCredentials extends AbstractSslCredentials {
+
+ private String type;
+ private String storeFile;
+ private String storePassword;
+ private String keyPassword;
+ private String keyAlias;
+
+ @Override
+ protected boolean canUse() {
+ return ResourceUtils.resourceExists(this, this.storeFile);
+ }
+
+ @Override
+ protected KeyStore loadKeyStore(boolean trustsOnly, char[] keyPasswordArray) throws IOException, GeneralSecurityException {
+ String keyStoreType = StringUtils.isEmpty(this.type) ? KeyStore.getDefaultType() : this.type;
+ KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+ try (InputStream tsFileInputStream = ResourceUtils.getInputStream(this, this.storeFile)) {
+ keyStore.load(tsFileInputStream, StringUtils.isEmpty(this.storePassword) ? new char[0] : this.storePassword.toCharArray());
+ }
+ return keyStore;
+ }
+}
diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/PemSslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/PemSslCredentials.java
new file mode 100644
index 0000000000..0575d68149
--- /dev/null
+++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/PemSslCredentials.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright © 2016-2021 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.common.transport.config.ssl;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMDecryptorProvider;
+import org.bouncycastle.openssl.PEMEncryptedKeyPair;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
+import org.thingsboard.server.common.data.ResourceUtils;
+import org.thingsboard.server.common.data.StringUtils;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class PemSslCredentials extends AbstractSslCredentials {
+
+ private String certFile;
+ private String keyFile;
+ private String keyPassword;
+ private final String keyAlias = "serveralias";
+
+ @Override
+ protected boolean canUse() {
+ return ResourceUtils.resourceExists(this, this.certFile);
+ }
+
+ @Override
+ protected KeyStore loadKeyStore(boolean trustsOnly, char[] keyPasswordArray) throws IOException, GeneralSecurityException {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ List certificates = new ArrayList<>();
+ PrivateKey privateKey = null;
+ JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter();
+ JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter();
+ try (InputStream inStream = ResourceUtils.getInputStream(this, this.certFile)) {
+ try (PEMParser pemParser = new PEMParser(new InputStreamReader(inStream))) {
+ Object object;
+ while((object = pemParser.readObject()) != null) {
+ if (object instanceof X509CertificateHolder) {
+ X509Certificate x509Cert = certConverter.getCertificate((X509CertificateHolder) object);
+ certificates.add(x509Cert);
+ } else if (object instanceof PEMEncryptedKeyPair) {
+ PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(keyPasswordArray);
+ privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate();
+ } else if (object instanceof PEMKeyPair) {
+ privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate();
+ } else if (object instanceof PrivateKeyInfo) {
+ privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object);
+ }
+ }
+ }
+ }
+ if (privateKey == null && !StringUtils.isEmpty(this.keyFile)) {
+ if (ResourceUtils.resourceExists(this, this.keyFile)) {
+ try (InputStream inStream = ResourceUtils.getInputStream(this, this.keyFile)) {
+ try (PEMParser pemParser = new PEMParser(new InputStreamReader(inStream))) {
+ Object object;
+ while ((object = pemParser.readObject()) != null) {
+ if (object instanceof PEMEncryptedKeyPair) {
+ PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(keyPasswordArray);
+ privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate();
+ break;
+ } else if (object instanceof PEMKeyPair) {
+ privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate();
+ break;
+ } else if (object instanceof PrivateKeyInfo) {
+ privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (certificates.isEmpty()) {
+ throw new IllegalArgumentException("No certificates found in certFile: " + this.certFile);
+ }
+ if (privateKey == null && !trustsOnly) {
+ throw new IllegalArgumentException("Unable to load private key neither from certFile: " + this.certFile + " nor from keyFile: " + this.keyFile);
+ }
+ KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ keyStore.load(null);
+ List unique = certificates.stream().distinct().collect(Collectors.toList());
+ for (int i = 0; i < unique.size(); i++) {
+ keyStore.setCertificateEntry("root-" + i, unique.get(i));
+ }
+ if (privateKey != null) {
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ CertPath certPath = factory.generateCertPath(certificates);
+ List extends Certificate> path = certPath.getCertificates();
+ Certificate[] x509Certificates = path.toArray(new Certificate[0]);
+ keyStore.setKeyEntry(this.keyAlias, privateKey, keyPasswordArray, x509Certificates);
+ }
+ return keyStore;
+ }
+}
diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java
new file mode 100644
index 0000000000..ef412815d7
--- /dev/null
+++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright © 2016-2021 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.common.transport.config.ssl;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.X509Certificate;
+
+public interface SslCredentials {
+
+ void init(boolean trustsOnly) throws IOException, GeneralSecurityException;
+
+ PrivateKey getPrivateKey();
+
+ PublicKey getPublicKey();
+
+ X509Certificate[] getCertificateChain();
+
+ X509Certificate[] getTrustedCertificates();
+
+ TrustManagerFactory createTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException;
+
+ KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException;
+
+}
diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsConfig.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsConfig.java
new file mode 100644
index 0000000000..8b43f36574
--- /dev/null
+++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsConfig.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright © 2016-2021 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.common.transport.config.ssl;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.PostConstruct;
+
+@Slf4j
+@Data
+public class SslCredentialsConfig {
+
+ private boolean enabled = true;
+ private SslCredentialsType type;
+ private PemSslCredentials pem;
+ private KeystoreSslCredentials keystore;
+
+ private SslCredentials credentials;
+
+ private final String name;
+ private final boolean trustsOnly;
+
+ public SslCredentialsConfig(String name, boolean trustsOnly) {
+ this.name = name;
+ this.trustsOnly = trustsOnly;
+ }
+
+ @PostConstruct
+ public void init() {
+ if (this.enabled) {
+ log.info("{}: Initializing SSL credentials.", name);
+ if (SslCredentialsType.PEM.equals(type) && pem.canUse()) {
+ this.credentials = this.pem;
+ } else if (keystore.canUse()) {
+ if (SslCredentialsType.PEM.equals(type)) {
+ log.warn("{}: Specified PEM configuration is not valid. Using SSL keystore configuration as fallback.", name);
+ }
+ this.credentials = this.keystore;
+ } else {
+ throw new RuntimeException(name + ": Invalid SSL credentials configuration. None of the PEM or KEYSTORE configurations can be used!");
+ }
+ try {
+ this.credentials.init(this.trustsOnly);
+ } catch (Exception e) {
+ throw new RuntimeException(name + ": Failed to init SSL credentials configuration.", e);
+ }
+ } else {
+ log.info("{}: Skipping initialization of disabled SSL credentials.", name);
+ }
+ }
+
+}
diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsType.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsType.java
new file mode 100644
index 0000000000..64115e57b6
--- /dev/null
+++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentialsType.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright © 2016-2021 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.common.transport.config.ssl;
+
+public enum SslCredentialsType {
+ PEM,
+ KEYSTORE
+}
diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml
index 9aab46b824..adaffed7de 100644
--- a/transport/coap/src/main/resources/tb-coap-transport.yml
+++ b/transport/coap/src/main/resources/tb-coap-transport.yml
@@ -98,17 +98,33 @@ transport:
bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}"
# CoAP DTLS bind port
bind_port: "${COAP_DTLS_BIND_PORT:5684}"
- # Path to the key store that holds the certificate
- key_store: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
- # Password used to access the key store
- key_store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
- # Password used to access the key
- key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
- # Key alias
- key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
- # Skip certificate validity check for client certificates.
- skip_validity_check_for_client_cert: "${COAP_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
+ # Server DTLS credentials
+ credentials:
+ # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
+ type: "${COAP_DTLS_CREDENTIALS_TYPE:PEM}"
+ # PEM server credentials
+ pem:
+ # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
+ cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}"
+ # Path to the server certificate private key file (optional)
+ key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}"
+ # Server certificate private key password (optional)
+ key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}"
+ # Keystore server credentials
+ keystore:
+ # Type of the key store
+ type: "${COAP_DTLS_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the SSL certificate
+ store_file: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
+ # Password used to access the key store
+ store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
+ # Password used to access the key
+ key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
+ # Key alias
+ key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
x509:
+ # Skip certificate validity check for client certificates.
+ skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}"
dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}"
sessions:
diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml
index 4280ccb1af..be5bb62a00 100644
--- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml
+++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml
@@ -111,9 +111,33 @@ transport:
security:
bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}"
bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}"
+ # Server X509 Certificates support
+ credentials:
+ # Whether to enable LWM2M server X509 Certificate/RPK support
+ enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}"
+ # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
+ type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}"
+ # PEM server credentials
+ pem:
+ # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
+ cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}"
+ # Path to the server certificate private key file (optional)
+ key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}"
+ # Server certificate private key password (optional)
+ key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}"
+ # Keystore server credentials
+ keystore:
+ # Type of the key store
+ type: "${LWM2M_SERVER_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the SSL certificate
+ store_file: "${LWM2M_SERVER_KEY_STORE:lwm2mserver.jks}"
+ # Password used to access the key store
+ store_password: "${LWM2M_SERVER_KEY_STORE_PASSWORD:server_ks_password}"
+ # Password used to access the key
+ key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_key_password}"
+ # Key alias
+ key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
# Only Certificate_x509:
- key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
- key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}"
skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
bootstrap:
enable: "${LWM2M_ENABLED_BS:true}"
@@ -123,18 +147,51 @@ transport:
security:
bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}"
bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}"
- # Only Certificate_x509:
- key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
- key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}"
+ # Bootstrap server X509 Certificates support
+ credentials:
+ # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support
+ enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}"
+ # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
+ type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}"
+ # PEM server credentials
+ pem:
+ # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
+ cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}"
+ # Path to the server certificate private key file (optional)
+ key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}"
+ # Server certificate private key password (optional)
+ key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}"
+ # Keystore server credentials
+ keystore:
+ # Type of the key store
+ type: "${LWM2M_BS_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the SSL certificate
+ store_file: "${LWM2M_BS_KEY_STORE:lwm2mserver.jks}"
+ # Password used to access the key store
+ store_password: "${LWM2M_BS_KEY_STORE_PASSWORD:server_ks_password}"
+ # Password used to access the key
+ key_password: "${LWM2M_BS_KEY_PASSWORD:server_key_password}"
+ # Key alias
+ key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
security:
- # Certificate_x509:
- # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
- # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
- key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
- # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks"
- key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}"
- key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}"
- root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}"
+ # X509 trust certificates
+ trust-credentials:
+ # Whether to load X509 trust certificates
+ enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}"
+ # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore)
+ type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}"
+ # PEM certificates
+ pem:
+ # Path to the certificates file (holds trust certificates)
+ cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mserver.pem}"
+ # Keystore with trust certificates
+ keystore:
+ # Type of the key store
+ type: "${LWM2M_TRUST_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the X509 certificates
+ store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mserver.jks}"
+ # Password used to access the key store
+ store_password: "${LWM2M_TRUST_KEY_STORE_PASSWORD:server_ks_password}"
recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
timeout: "${LWM2M_TIMEOUT:120000}"
diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml
index e0d0144d84..75538e6f61 100644
--- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml
+++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml
@@ -106,14 +106,28 @@ transport:
bind_port: "${MQTT_SSL_BIND_PORT:8883}"
# SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext
protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}"
- # Path to the key store that holds the SSL certificate
- key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
- # Password used to access the key store
- key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
- # Password used to access the key
- key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
- # Type of the key store
- key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
+ # Server SSL credentials
+ credentials:
+ # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
+ type: "${MQTT_SSL_CREDENTIALS_TYPE:PEM}"
+ # PEM server credentials
+ pem:
+ # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
+ cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}"
+ # Path to the server certificate private key file (optional)
+ key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}"
+ # Server certificate private key password (optional)
+ key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}"
+ # Keystore server credentials
+ keystore:
+ # Type of the key store
+ type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
+ # Path to the key store that holds the SSL certificate
+ store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
+ # Password used to access the key store
+ store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
+ # Password used to access the key
+ key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
# Skip certificate validity check for client certificates.
skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
sessions: