Commit 362ccf9f31a026a7195eb42c2774402e7767bc74

Authored by Igor Kulikov
1 parent 70fdc7d0

Unified transport SSL credentials

Showing 21 changed files with 883 additions and 239 deletions
... ... @@ -22,28 +22,11 @@ import org.eclipse.leshan.core.util.Hex;
22 22 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
23 23 import org.springframework.stereotype.Service;
24 24 import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig;
  25 +import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
25 26 import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig;
26 27 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig;
27 28 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
28 29
29   -import java.math.BigInteger;
30   -import java.security.AlgorithmParameters;
31   -import java.security.GeneralSecurityException;
32   -import java.security.KeyFactory;
33   -import java.security.KeyStore;
34   -import java.security.KeyStoreException;
35   -import java.security.NoSuchAlgorithmException;
36   -import java.security.PrivateKey;
37   -import java.security.PublicKey;
38   -import java.security.UnrecoverableKeyException;
39   -import java.security.cert.CertificateEncodingException;
40   -import java.security.cert.X509Certificate;
41   -import java.security.spec.ECGenParameterSpec;
42   -import java.security.spec.ECParameterSpec;
43   -import java.security.spec.ECPoint;
44   -import java.security.spec.ECPublicKeySpec;
45   -import java.security.spec.KeySpec;
46   -
47 30 @Slf4j
48 31 @Service
49 32 @RequiredArgsConstructor
... ... @@ -72,10 +55,9 @@ public class LwM2MServerSecurityInfoRepository {
72 55
73 56 private String getPublicKey(LwM2MSecureServerConfig config) {
74 57 try {
75   - KeyStore keyStore = serverConfig.getKeyStoreValue();
76   - if (keyStore != null) {
77   - X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(config.getCertificateAlias());
78   - return Hex.encodeHexString(serverCertificate.getPublicKey().getEncoded());
  58 + SslCredentials sslCredentials = config.getSslCredentials();
  59 + if (sslCredentials != null) {
  60 + return Hex.encodeHexString(sslCredentials.getPublicKey().getEncoded());
79 61 }
80 62 } catch (Exception e) {
81 63 log.trace("Failed to fetch public key from key store!", e);
... ...
... ... @@ -619,14 +619,28 @@ transport:
619 619 bind_port: "${MQTT_SSL_BIND_PORT:8883}"
620 620 # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext
621 621 protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}"
622   - # Path to the key store that holds the SSL certificate
623   - key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
624   - # Password used to access the key store
625   - key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
626   - # Password used to access the key
627   - key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
628   - # Type of the key store
629   - key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
  622 + # Server SSL credentials
  623 + credentials:
  624 + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
  625 + type: "${MQTT_SSL_CREDENTIALS_TYPE:PEM}"
  626 + # PEM server credentials
  627 + pem:
  628 + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
  629 + cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}"
  630 + # Path to the server certificate private key file (optional)
  631 + key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}"
  632 + # Server certificate private key password (optional)
  633 + key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}"
  634 + # Keystore server credentials
  635 + keystore:
  636 + # Type of the key store
  637 + type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
  638 + # Path to the key store that holds the SSL certificate
  639 + store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
  640 + # Password used to access the key store
  641 + store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
  642 + # Password used to access the key
  643 + key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
630 644 # Skip certificate validity check for client certificates.
631 645 skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
632 646 # Local CoAP transport parameters
... ... @@ -645,14 +659,30 @@ transport:
645 659 bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}"
646 660 # CoAP DTLS bind port
647 661 bind_port: "${COAP_DTLS_BIND_PORT:5684}"
648   - # Path to the key store that holds the certificate
649   - key_store: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
650   - # Password used to access the key store
651   - key_store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
652   - # Password used to access the key
653   - key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
654   - # Key alias
655   - key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
  662 + # Server DTLS credentials
  663 + credentials:
  664 + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
  665 + type: "${COAP_DTLS_CREDENTIALS_TYPE:PEM}"
  666 + # PEM server credentials
  667 + pem:
  668 + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
  669 + cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}"
  670 + # Path to the server certificate private key file (optional)
  671 + key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}"
  672 + # Server certificate private key password (optional)
  673 + key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}"
  674 + # Keystore server credentials
  675 + keystore:
  676 + # Type of the key store
  677 + type: "${COAP_DTLS_KEY_STORE_TYPE:JKS}"
  678 + # Path to the key store that holds the SSL certificate
  679 + store_file: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
  680 + # Password used to access the key store
  681 + store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
  682 + # Password used to access the key
  683 + key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
  684 + # Key alias
  685 + key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
656 686 x509:
657 687 # Skip certificate validity check for client certificates.
658 688 skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
... ... @@ -669,9 +699,33 @@ transport:
669 699 security:
670 700 bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}"
671 701 bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}"
  702 + # Server X509 Certificates support
  703 + credentials:
  704 + # Whether to enable LWM2M server X509 Certificate/RPK support
  705 + enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}"
  706 + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
  707 + type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}"
  708 + # PEM server credentials
  709 + pem:
  710 + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
  711 + cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}"
  712 + # Path to the server certificate private key file (optional)
  713 + key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}"
  714 + # Server certificate private key password (optional)
  715 + key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}"
  716 + # Keystore server credentials
  717 + keystore:
  718 + # Type of the key store
  719 + type: "${LWM2M_SERVER_KEY_STORE_TYPE:JKS}"
  720 + # Path to the key store that holds the SSL certificate
  721 + store_file: "${LWM2M_SERVER_KEY_STORE:lwm2mserver.jks}"
  722 + # Password used to access the key store
  723 + store_password: "${LWM2M_SERVER_KEY_STORE_PASSWORD:server_ks_password}"
  724 + # Password used to access the key
  725 + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_key_password}"
  726 + # Key alias
  727 + key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
672 728 # Only Certificate_x509:
673   - key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
674   - key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}"
675 729 skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
676 730 bootstrap:
677 731 enable: "${LWM2M_ENABLED_BS:true}"
... ... @@ -681,18 +735,51 @@ transport:
681 735 security:
682 736 bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}"
683 737 bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}"
684   - # Only Certificate_x509:
685   - key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
686   - key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}"
  738 + # Bootstrap server X509 Certificates support
  739 + credentials:
  740 + # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support
  741 + enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}"
  742 + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
  743 + type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}"
  744 + # PEM server credentials
  745 + pem:
  746 + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
  747 + cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}"
  748 + # Path to the server certificate private key file (optional)
  749 + key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}"
  750 + # Server certificate private key password (optional)
  751 + key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}"
  752 + # Keystore server credentials
  753 + keystore:
  754 + # Type of the key store
  755 + type: "${LWM2M_BS_KEY_STORE_TYPE:JKS}"
  756 + # Path to the key store that holds the SSL certificate
  757 + store_file: "${LWM2M_BS_KEY_STORE:lwm2mserver.jks}"
  758 + # Password used to access the key store
  759 + store_password: "${LWM2M_BS_KEY_STORE_PASSWORD:server_ks_password}"
  760 + # Password used to access the key
  761 + key_password: "${LWM2M_BS_KEY_PASSWORD:server_key_password}"
  762 + # Key alias
  763 + key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
687 764 security:
688   - # Certificate_x509:
689   - # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
690   - # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
691   - key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
692   - # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks"
693   - key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}"
694   - key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}"
695   - root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}"
  765 + # X509 trust certificates
  766 + trust-credentials:
  767 + # Whether to load X509 trust certificates
  768 + enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}"
  769 + # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore)
  770 + type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}"
  771 + # PEM certificates
  772 + pem:
  773 + # Path to the certificates file (holds trust certificates)
  774 + cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mserver.pem}"
  775 + # Keystore with trust certificates
  776 + keystore:
  777 + # Type of the key store
  778 + type: "${LWM2M_TRUST_KEY_STORE_TYPE:JKS}"
  779 + # Path to the key store that holds the X509 certificates
  780 + store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mserver.jks}"
  781 + # Password used to access the key store
  782 + store_password: "${LWM2M_TRUST_KEY_STORE_PASSWORD:server_ks_password}"
696 783 recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
697 784 recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
698 785 timeout: "${LWM2M_TIMEOUT:120000}"
... ...
... ... @@ -20,11 +20,16 @@ import org.eclipse.californium.elements.util.SslContextUtil;
20 20 import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
21 21 import org.eclipse.californium.scandium.dtls.CertificateType;
22 22 import org.springframework.beans.factory.annotation.Autowired;
  23 +import org.springframework.beans.factory.annotation.Qualifier;
23 24 import org.springframework.beans.factory.annotation.Value;
24 25 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  26 +import org.springframework.boot.context.properties.ConfigurationProperties;
  27 +import org.springframework.context.annotation.Bean;
25 28 import org.springframework.stereotype.Component;
26 29 import org.thingsboard.server.common.data.ResourceUtils;
27 30 import org.thingsboard.server.common.transport.TransportService;
  31 +import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
  32 +import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
28 33 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
29 34
30 35 import java.io.IOException;
... ... @@ -45,17 +50,15 @@ public class TbCoapDtlsSettings {
45 50 @Value("${transport.coap.dtls.bind_port}")
46 51 private Integer port;
47 52
48   - @Value("${transport.coap.dtls.key_store}")
49   - private String keyStoreFile;
50   -
51   - @Value("${transport.coap.dtls.key_store_password}")
52   - private String keyStorePassword;
53   -
54   - @Value("${transport.coap.dtls.key_password}")
55   - private String keyPassword;
  53 + @Bean
  54 + @ConfigurationProperties(prefix = "transport.coap.dtls.credentials")
  55 + public SslCredentialsConfig coapDtlsCredentials() {
  56 + return new SslCredentialsConfig("COAP DTLS Credentials", false);
  57 + }
56 58
57   - @Value("${transport.coap.dtls.key_alias}")
58   - private String keyAlias;
  59 + @Autowired
  60 + @Qualifier("coapDtlsCredentials")
  61 + private SslCredentialsConfig coapDtlsCredentialsConfig;
59 62
60 63 @Value("${transport.coap.dtls.x509.skip_validity_check_for_client_cert:false}")
61 64 private boolean skipValidityCheckForClientCert;
... ... @@ -75,8 +78,9 @@ public class TbCoapDtlsSettings {
75 78 public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException {
76 79 DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder();
77 80 configBuilder.setAddress(getInetSocketAddress());
78   - String keyStoreFilePath = ResourceUtils.getUri(this, keyStoreFile);
79   - SslContextUtil.Credentials serverCredentials = loadServerCredentials(keyStoreFilePath);
  81 + SslCredentials sslCredentials = this.coapDtlsCredentialsConfig.getCredentials();
  82 + SslContextUtil.Credentials serverCredentials =
  83 + new SslContextUtil.Credentials(sslCredentials.getPrivateKey(), null, sslCredentials.getCertificateChain());
80 84 configBuilder.setServerOnly(true);
81 85 configBuilder.setClientAuthenticationRequired(false);
82 86 configBuilder.setClientAuthenticationWanted(true);
... ... @@ -94,15 +98,6 @@ public class TbCoapDtlsSettings {
94 98 return configBuilder.build();
95 99 }
96 100
97   - private SslContextUtil.Credentials loadServerCredentials(String keyStoreFilePath) {
98   - try {
99   - return SslContextUtil.loadCredentials(keyStoreFilePath, keyAlias, keyStorePassword.toCharArray(),
100   - keyPassword.toCharArray());
101   - } catch (GeneralSecurityException | IOException e) {
102   - throw new RuntimeException("Failed to load serverCredentials due to: ", e);
103   - }
104   - }
105   -
106 101 private InetSocketAddress getInetSocketAddress() throws UnknownHostException {
107 102 InetAddress addr = InetAddress.getByName(host);
108 103 return new InetSocketAddress(addr, port);
... ...
... ... @@ -27,6 +27,30 @@ import java.net.URL;
27 27 @Slf4j
28 28 public class ResourceUtils {
29 29
  30 + public static boolean resourceExists(Object classLoaderSource, String filePath) {
  31 + return resourceExists(classLoaderSource.getClass().getClassLoader(), filePath);
  32 + }
  33 +
  34 + public static boolean resourceExists(ClassLoader classLoader, String filePath) {
  35 + File resourceFile = new File(filePath);
  36 + if (resourceFile.exists()) {
  37 + return true;
  38 + } else {
  39 + InputStream classPathStream = classLoader.getResourceAsStream(filePath);
  40 + if (classPathStream != null) {
  41 + return true;
  42 + } else {
  43 + try {
  44 + URL url = Resources.getResource(filePath);
  45 + if (url != null) {
  46 + return true;
  47 + }
  48 + } catch (IllegalArgumentException e) {}
  49 + }
  50 + }
  51 + return false;
  52 + }
  53 +
30 54 public static InputStream getInputStream(Object classLoaderSource, String filePath) {
31 55 return getInputStream(classLoaderSource.getClass().getClassLoader(), filePath);
32 56 }
... ...
... ... @@ -27,6 +27,7 @@ import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
27 27 import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder;
28 28 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
29 29 import org.springframework.stereotype.Component;
  30 +import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
30 31 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore;
31 32 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore;
32 33 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigurationAdapter;
... ... @@ -114,49 +115,22 @@ public class LwM2MTransportBootstrapService {
114 115 }
115 116
116 117 private void setServerWithCredentials(LeshanBootstrapServerBuilder builder) {
117   - try {
118   - if (serverConfig.getKeyStoreValue() != null) {
119   - KeyStore keyStoreServer = serverConfig.getKeyStoreValue();
120   - if (this.setBuilderX509(builder)) {
121   - X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(serverConfig.getRootCertificateAlias());
122   - if (rootCAX509Cert != null) {
123   - X509Certificate[] trustedCertificates = new X509Certificate[1];
124   - trustedCertificates[0] = rootCAX509Cert;
125   - builder.setTrustedCertificates(trustedCertificates);
126   - } else {
127   - /* by default trust all */
128   - builder.setTrustedCertificates(new X509Certificate[0]);
129   - }
130   - }
  118 + if (this.bootstrapConfig.getSslCredentials() != null) {
  119 + SslCredentials sslCredentials = this.bootstrapConfig.getSslCredentials();
  120 + builder.setPublicKey(sslCredentials.getPublicKey());
  121 + builder.setPrivateKey(sslCredentials.getPrivateKey());
  122 + builder.setCertificateChain(sslCredentials.getCertificateChain());
  123 + if (this.serverConfig.getTrustSslCredentials() != null) {
  124 + builder.setTrustedCertificates(this.serverConfig.getTrustSslCredentials().getTrustedCertificates());
131 125 } else {
132 126 /* by default trust all */
133 127 builder.setTrustedCertificates(new X509Certificate[0]);
134   - log.info("Unable to load X509 files for BootStrapServer");
135   - this.pskMode = true;
136 128 }
137   - } catch (KeyStoreException ex) {
138   - log.error("[{}] Unable to load X509 files server", ex.getMessage());
  129 + } else {
  130 + /* by default trust all */
  131 + builder.setTrustedCertificates(new X509Certificate[0]);
  132 + log.info("Unable to load X509 files for BootStrapServer");
  133 + this.pskMode = true;
139 134 }
140 135 }
141   -
142   - private boolean setBuilderX509(LeshanBootstrapServerBuilder builder) {
143   - try {
144   - X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(serverConfig.getKeyStoreValue().getCertificateChain(this.bootstrapConfig.getCertificateAlias()));
145   - X509Certificate serverCertificate = certificateChain[0];
146   - PrivateKey privateKey = (PrivateKey) serverConfig.getKeyStoreValue().getKey(this.bootstrapConfig.getCertificateAlias(), serverConfig.getCertificatePassword() == null ? null : serverConfig.getCertificatePassword().toCharArray());
147   - PublicKey publicKey = serverCertificate.getPublicKey();
148   - if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) {
149   - builder.setPublicKey(serverCertificate.getPublicKey());
150   - builder.setPrivateKey(privateKey);
151   - builder.setCertificateChain(certificateChain);
152   - return true;
153   - } else {
154   - return false;
155   - }
156   - } catch (Exception ex) {
157   - log.error("[{}] Unable to load KeyStore files server", ex.getMessage());
158   - return false;
159   - }
160   - }
161   -
162 136 }
... ...
... ... @@ -15,6 +15,8 @@
15 15 */
16 16 package org.thingsboard.server.transport.lwm2m.config;
17 17
  18 +import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
  19 +
18 20 public interface LwM2MSecureServerConfig {
19 21
20 22 Integer getId();
... ... @@ -27,8 +29,6 @@ public interface LwM2MSecureServerConfig {
27 29
28 30 Integer getSecurePort();
29 31
30   - String getCertificateAlias();
31   -
32   - String getCertificatePassword();
  32 + SslCredentials getSslCredentials();
33 33
34 34 }
... ...
... ... @@ -17,9 +17,15 @@ package org.thingsboard.server.transport.lwm2m.config;
17 17
18 18 import lombok.Getter;
19 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.springframework.beans.factory.annotation.Qualifier;
20 22 import org.springframework.beans.factory.annotation.Value;
21 23 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  24 +import org.springframework.boot.context.properties.ConfigurationProperties;
  25 +import org.springframework.context.annotation.Bean;
22 26 import org.springframework.stereotype.Component;
  27 +import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
  28 +import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
23 29
24 30 @Slf4j
25 31 @Component
... ... @@ -46,12 +52,18 @@ public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig {
46 52 @Value("${transport.lwm2m.bootstrap.security.bind_port:}")
47 53 private Integer securePort;
48 54
49   - @Getter
50   - @Value("${transport.lwm2m.bootstrap.security.key_alias:}")
51   - private String certificateAlias;
  55 + @Bean
  56 + @ConfigurationProperties(prefix = "transport.lwm2m.bootstrap.security.credentials")
  57 + public SslCredentialsConfig lwm2mBootstrapCredentials() {
  58 + return new SslCredentialsConfig("LWM2M Bootstrap DTLS Credentials", false);
  59 + }
52 60
53   - @Getter
54   - @Value("${transport.lwm2m.bootstrap.security.key_password:}")
55   - private String certificatePassword;
  61 + @Autowired
  62 + @Qualifier("lwm2mBootstrapCredentials")
  63 + private SslCredentialsConfig credentialsConfig;
56 64
  65 + @Override
  66 + public SslCredentials getSslCredentials() {
  67 + return this.credentialsConfig.getCredentials();
  68 + }
57 69 }
... ...
... ... @@ -18,10 +18,16 @@ package org.thingsboard.server.transport.lwm2m.config;
18 18 import lombok.Getter;
19 19 import lombok.Setter;
20 20 import lombok.extern.slf4j.Slf4j;
  21 +import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.beans.factory.annotation.Qualifier;
21 23 import org.springframework.beans.factory.annotation.Value;
22 24 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  25 +import org.springframework.boot.context.properties.ConfigurationProperties;
  26 +import org.springframework.context.annotation.Bean;
23 27 import org.springframework.stereotype.Component;
24 28 import org.thingsboard.server.common.data.ResourceUtils;
  29 +import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
  30 +import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
25 31
26 32 import javax.annotation.PostConstruct;
27 33 import java.io.InputStream;
... ... @@ -65,26 +71,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
65 71 private int cleanPeriodInSec;
66 72
67 73 @Getter
68   - @Value("${transport.lwm2m.security.key_store_type:}")
69   - private String keyStoreType;
70   -
71   - @Getter
72   - @Value("${transport.lwm2m.security.key_store:}")
73   - private String keyStoreFilePath;
74   -
75   - @Getter
76   - @Setter
77   - private KeyStore keyStoreValue;
78   -
79   - @Getter
80   - @Value("${transport.lwm2m.security.key_store_password:}")
81   - private String keyStorePassword;
82   -
83   - @Getter
84   - @Value("${transport.lwm2m.security.root_alias:}")
85   - private String rootCertificateAlias;
86   -
87   - @Getter
88 74 @Value("${transport.lwm2m.server.id:}")
89 75 private Integer id;
90 76
... ... @@ -105,14 +91,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
105 91 private Integer securePort;
106 92
107 93 @Getter
108   - @Value("${transport.lwm2m.server.security.key_alias:}")
109   - private String certificateAlias;
110   -
111   - @Getter
112   - @Value("${transport.lwm2m.server.security.key_password:}")
113   - private String certificatePassword;
114   -
115   - @Getter
116 94 @Value("${transport.lwm2m.log_max_length:}")
117 95 private int logMaxLength;
118 96
... ... @@ -124,15 +102,32 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
124 102 @Value("${transport.lwm2m.paging_transmission_window:10000}")
125 103 private long pagingTransmissionWindow;
126 104
127   - @PostConstruct
128   - public void init() {
129   - try {
130   - InputStream keyStoreInputStream = ResourceUtils.getInputStream(this, keyStoreFilePath);
131   - keyStoreValue = KeyStore.getInstance(keyStoreType);
132   - keyStoreValue.load(keyStoreInputStream, keyStorePassword == null ? null : keyStorePassword.toCharArray());
133   - } catch (Exception e) {
134   - log.info("Unable to lookup LwM2M keystore. Reason: {}, {}", keyStoreFilePath, e.getMessage());
135   - }
  105 + @Bean
  106 + @ConfigurationProperties(prefix = "transport.lwm2m.server.security.credentials")
  107 + public SslCredentialsConfig lwm2mServerCredentials() {
  108 + return new SslCredentialsConfig("LWM2M Server DTLS Credentials", false);
  109 + }
  110 +
  111 + @Autowired
  112 + @Qualifier("lwm2mServerCredentials")
  113 + private SslCredentialsConfig credentialsConfig;
  114 +
  115 + @Bean
  116 + @ConfigurationProperties(prefix = "transport.lwm2m.security.trust-credentials")
  117 + public SslCredentialsConfig lwm2mTrustCredentials() {
  118 + return new SslCredentialsConfig("LWM2M Trust Credentials", true);
136 119 }
137 120
  121 + @Autowired
  122 + @Qualifier("lwm2mTrustCredentials")
  123 + private SslCredentialsConfig trustCredentialsConfig;
  124 +
  125 + @Override
  126 + public SslCredentials getSslCredentials() {
  127 + return this.credentialsConfig.getCredentials();
  128 + }
  129 +
  130 + public SslCredentials getTrustSslCredentials() {
  131 + return this.trustCredentialsConfig.getCredentials();
  132 + }
138 133 }
... ...
... ... @@ -87,12 +87,8 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
87 87 try {
88 88 /* by default trust all */
89 89 X509Certificate[] trustedCertificates = new X509Certificate[0];
90   - if (config.getKeyStoreValue() != null) {
91   - X509Certificate rootCAX509Cert = (X509Certificate) config.getKeyStoreValue().getCertificate(config.getRootCertificateAlias());
92   - if (rootCAX509Cert != null) {
93   - trustedCertificates = new X509Certificate[1];
94   - trustedCertificates[0] = rootCAX509Cert;
95   - }
  90 + if (config.getTrustSslCredentials() != null) {
  91 + trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates();
96 92 }
97 93 staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates);
98 94 } catch (Exception e) {
... ...
... ... @@ -29,6 +29,7 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider;
29 29 import org.springframework.stereotype.Component;
30 30 import org.thingsboard.server.cache.ota.OtaPackageDataCache;
31 31 import org.thingsboard.server.common.data.DataConstants;
  32 +import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
32 33 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
33 34 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
34 35 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer;
... ... @@ -141,7 +142,11 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
141 142 }
142 143
143 144 private void setServerWithCredentials(LeshanServerBuilder builder, DtlsConnectorConfig.Builder dtlsConfig) {
144   - if (config.getKeyStoreValue() != null && this.setBuilderX509(builder)) {
  145 + if (this.config.getSslCredentials() != null) {
  146 + SslCredentials sslCredentials = this.config.getSslCredentials();
  147 + builder.setPublicKey(sslCredentials.getPublicKey());
  148 + builder.setPrivateKey(sslCredentials.getPrivateKey());
  149 + builder.setCertificateChain(sslCredentials.getCertificateChain());
145 150 dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier);
146 151 builder.setAuthorizer(authorizer);
147 152 dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES);
... ... @@ -153,26 +158,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
153 158 }
154 159 }
155 160
156   - private boolean setBuilderX509(LeshanServerBuilder builder) {
157   - try {
158   - X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(config.getKeyStoreValue().getCertificateChain(config.getCertificateAlias()));
159   - X509Certificate serverCertificate = certificateChain[0];
160   - PrivateKey privateKey = (PrivateKey) config.getKeyStoreValue().getKey(config.getCertificateAlias(), config.getCertificatePassword() == null ? null : config.getCertificatePassword().toCharArray());
161   - PublicKey publicKey = serverCertificate.getPublicKey();
162   - if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) {
163   - builder.setPublicKey(serverCertificate.getPublicKey());
164   - builder.setPrivateKey(privateKey);
165   - builder.setCertificateChain(certificateChain);
166   - return true;
167   - } else {
168   - return false;
169   - }
170   - } catch (Exception ex) {
171   - log.error("[{}] Unable to load KeyStore files server", ex.getMessage());
172   - return false;
173   - }
174   - }
175   -
176 161 @Override
177 162 public String getName() {
178 163 return DataConstants.LWM2M_TRANSPORT_NAME;
... ...
... ... @@ -18,16 +18,20 @@ package org.thingsboard.server.transport.mqtt;
18 18 import io.netty.handler.ssl.SslHandler;
19 19 import lombok.extern.slf4j.Slf4j;
20 20 import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.springframework.beans.factory.annotation.Qualifier;
21 22 import org.springframework.beans.factory.annotation.Value;
22 23 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  24 +import org.springframework.boot.context.properties.ConfigurationProperties;
  25 +import org.springframework.context.annotation.Bean;
23 26 import org.springframework.stereotype.Component;
24 27 import org.springframework.util.StringUtils;
25 28 import org.thingsboard.server.common.data.DeviceTransportType;
26   -import org.thingsboard.server.common.data.ResourceUtils;
27 29 import org.thingsboard.server.common.msg.EncryptionUtil;
28 30 import org.thingsboard.server.common.transport.TransportService;
29 31 import org.thingsboard.server.common.transport.TransportServiceCallback;
30 32 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
  33 +import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
  34 +import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
31 35 import org.thingsboard.server.common.transport.util.SslUtil;
32 36 import org.thingsboard.server.gen.transport.TransportProtos;
33 37
... ... @@ -38,8 +42,6 @@ import javax.net.ssl.SSLEngine;
38 42 import javax.net.ssl.TrustManager;
39 43 import javax.net.ssl.TrustManagerFactory;
40 44 import javax.net.ssl.X509TrustManager;
41   -import java.io.InputStream;
42   -import java.security.KeyStore;
43 45 import java.security.cert.CertificateEncodingException;
44 46 import java.security.cert.CertificateException;
45 47 import java.security.cert.X509Certificate;
... ... @@ -56,18 +58,20 @@ public class MqttSslHandlerProvider {
56 58
57 59 @Value("${transport.mqtt.ssl.protocol}")
58 60 private String sslProtocol;
59   - @Value("${transport.mqtt.ssl.key_store}")
60   - private String keyStoreFile;
61   - @Value("${transport.mqtt.ssl.key_store_password}")
62   - private String keyStorePassword;
63   - @Value("${transport.mqtt.ssl.key_password}")
64   - private String keyPassword;
65   - @Value("${transport.mqtt.ssl.key_store_type}")
66   - private String keyStoreType;
67 61
68 62 @Autowired
69 63 private TransportService transportService;
70 64
  65 + @Bean
  66 + @ConfigurationProperties(prefix = "transport.mqtt.ssl.credentials")
  67 + public SslCredentialsConfig mqttSslCredentials() {
  68 + return new SslCredentialsConfig("MQTT SSL Credentials", false);
  69 + }
  70 +
  71 + @Autowired
  72 + @Qualifier("mqttSslCredentials")
  73 + private SslCredentialsConfig mqttSslCredentialsConfig;
  74 +
71 75 private SSLContext sslContext;
72 76
73 77 public SslHandler getSslHandler() {
... ... @@ -86,19 +90,9 @@ public class MqttSslHandlerProvider {
86 90
87 91 private SSLContext createSslContext() {
88 92 try {
89   - TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
90   - KeyStore trustStore = KeyStore.getInstance(keyStoreType);
91   - try (InputStream tsFileInputStream = ResourceUtils.getInputStream(this, keyStoreFile)) {
92   - trustStore.load(tsFileInputStream, keyStorePassword.toCharArray());
93   - }
94   - tmFactory.init(trustStore);
95   -
96   - KeyStore ks = KeyStore.getInstance(keyStoreType);
97   - try (InputStream ksFileInputStream = ResourceUtils.getInputStream(this, keyStoreFile)) {
98   - ks.load(ksFileInputStream, keyStorePassword.toCharArray());
99   - }
100   - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
101   - kmf.init(ks, keyPassword.toCharArray());
  93 + SslCredentials sslCredentials = this.mqttSslCredentialsConfig.getCredentials();
  94 + TrustManagerFactory tmFactory = sslCredentials.createTrustManagerFactory();
  95 + KeyManagerFactory kmf = sslCredentials.createKeyManagerFactory();
102 96
103 97 KeyManager[] km = kmf.getKeyManagers();
104 98 TrustManager x509wrapped = getX509TrustManager(tmFactory);
... ...
... ... @@ -129,6 +129,14 @@
129 129 <groupId>org.eclipse.leshan</groupId>
130 130 <artifactId>leshan-server-cf</artifactId>
131 131 </dependency>
  132 + <dependency>
  133 + <groupId>org.bouncycastle</groupId>
  134 + <artifactId>bcprov-jdk15on</artifactId>
  135 + </dependency>
  136 + <dependency>
  137 + <groupId>org.bouncycastle</groupId>
  138 + <artifactId>bcpkix-jdk15on</artifactId>
  139 + </dependency>
132 140 </dependencies>
133 141
134 142 <build>
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.transport.config.ssl;
  17 +
  18 +import org.thingsboard.server.common.data.StringUtils;
  19 +
  20 +import javax.net.ssl.KeyManagerFactory;
  21 +import javax.net.ssl.TrustManagerFactory;
  22 +import java.io.IOException;
  23 +import java.security.GeneralSecurityException;
  24 +import java.security.KeyStore;
  25 +import java.security.KeyStore.PrivateKeyEntry;
  26 +import java.security.KeyStoreException;
  27 +import java.security.NoSuchAlgorithmException;
  28 +import java.security.PrivateKey;
  29 +import java.security.PublicKey;
  30 +import java.security.UnrecoverableEntryException;
  31 +import java.security.UnrecoverableKeyException;
  32 +import java.security.cert.Certificate;
  33 +import java.security.cert.X509Certificate;
  34 +import java.util.Collections;
  35 +import java.util.Enumeration;
  36 +import java.util.HashSet;
  37 +import java.util.Set;
  38 +
  39 +public abstract class AbstractSslCredentials implements SslCredentials {
  40 +
  41 + private char[] keyPasswordArray;
  42 +
  43 + private KeyStore keyStore;
  44 +
  45 + private PrivateKey privateKey;
  46 +
  47 + private PublicKey publicKey;
  48 +
  49 + private X509Certificate[] chain;
  50 +
  51 + private X509Certificate[] trusts;
  52 +
  53 + @Override
  54 + public void init(boolean trustsOnly) throws IOException, GeneralSecurityException {
  55 + String keyPassword = getKeyPassword();
  56 + if (StringUtils.isEmpty(keyPassword)) {
  57 + this.keyPasswordArray = new char[0];
  58 + } else {
  59 + this.keyPasswordArray = keyPassword.toCharArray();
  60 + }
  61 + this.keyStore = this.loadKeyStore(trustsOnly, this.keyPasswordArray);
  62 + Set<X509Certificate> trustedCerts = getTrustedCerts(this.keyStore);
  63 + this.trusts = trustedCerts.toArray(new X509Certificate[0]);
  64 + if (!trustsOnly) {
  65 + PrivateKeyEntry privateKeyEntry = null;
  66 + String keyAlias = this.getKeyAlias();
  67 + if (!StringUtils.isEmpty(keyAlias)) {
  68 + privateKeyEntry = tryGetPrivateKeyEntry(this.keyStore, keyAlias, this.keyPasswordArray);
  69 + } else {
  70 + for (Enumeration<String> e = this.keyStore.aliases(); e.hasMoreElements(); ) {
  71 + String alias = e.nextElement();
  72 + privateKeyEntry = tryGetPrivateKeyEntry(this.keyStore, alias, this.keyPasswordArray);
  73 + if (privateKeyEntry != null) {
  74 + break;
  75 + }
  76 + }
  77 + }
  78 + if (privateKeyEntry == null) {
  79 + throw new IllegalArgumentException("Failed to get private key from the keystore or pem files. " +
  80 + "Please check if the private key exists in the keystore or pem files and if the provided private key password is valid.");
  81 + }
  82 + this.chain = asX509Certificates(privateKeyEntry.getCertificateChain());
  83 + this.privateKey = privateKeyEntry.getPrivateKey();
  84 + if (this.chain.length > 0) {
  85 + this.publicKey = this.chain[0].getPublicKey();
  86 + }
  87 + }
  88 + }
  89 +
  90 + @Override
  91 + public PrivateKey getPrivateKey() {
  92 + return this.privateKey;
  93 + }
  94 +
  95 + @Override
  96 + public PublicKey getPublicKey() {
  97 + return this.publicKey;
  98 + }
  99 +
  100 + @Override
  101 + public X509Certificate[] getCertificateChain() {
  102 + return this.chain;
  103 + }
  104 +
  105 + @Override
  106 + public X509Certificate[] getTrustedCertificates() {
  107 + return this.trusts;
  108 + }
  109 +
  110 + @Override
  111 + public TrustManagerFactory createTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException {
  112 + TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
  113 + tmFactory.init(this.keyStore);
  114 + return tmFactory;
  115 + }
  116 +
  117 + @Override
  118 + public KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
  119 + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
  120 + kmf.init(this.keyStore, this.keyPasswordArray);
  121 + return kmf;
  122 + }
  123 +
  124 + protected abstract boolean canUse();
  125 +
  126 + protected abstract String getKeyPassword();
  127 +
  128 + protected abstract String getKeyAlias();
  129 +
  130 + protected abstract KeyStore loadKeyStore(boolean isPrivateKeyRequired, char[] keyPasswordArray) throws IOException, GeneralSecurityException;
  131 +
  132 + private static X509Certificate[] asX509Certificates(Certificate[] certificates) {
  133 + if (null == certificates || 0 == certificates.length) {
  134 + throw new IllegalArgumentException("certificates missing!");
  135 + }
  136 + X509Certificate[] x509Certificates = new X509Certificate[certificates.length];
  137 + for (int index = 0; certificates.length > index; ++index) {
  138 + if (null == certificates[index]) {
  139 + throw new IllegalArgumentException("[" + index + "] is null!");
  140 + }
  141 + try {
  142 + x509Certificates[index] = (X509Certificate) certificates[index];
  143 + } catch (ClassCastException e) {
  144 + throw new IllegalArgumentException("[" + index + "] is not a x509 certificate! Instead it's a "
  145 + + certificates[index].getClass().getName());
  146 + }
  147 + }
  148 + return x509Certificates;
  149 + }
  150 +
  151 + private static PrivateKeyEntry tryGetPrivateKeyEntry(KeyStore keyStore, String alias, char[] pwd) {
  152 + PrivateKeyEntry entry = null;
  153 + try {
  154 + if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
  155 + try {
  156 + entry = (KeyStore.PrivateKeyEntry) keyStore
  157 + .getEntry(alias, new KeyStore.PasswordProtection(pwd));
  158 + } catch (UnsupportedOperationException e) {
  159 + PrivateKey key = (PrivateKey) keyStore.getKey(alias, pwd);
  160 + Certificate[] certs = keyStore.getCertificateChain(alias);
  161 + entry = new KeyStore.PrivateKeyEntry(key, certs);
  162 + }
  163 + }
  164 + } catch (KeyStoreException | UnrecoverableEntryException | NoSuchAlgorithmException ignored) {}
  165 + return entry;
  166 + }
  167 +
  168 + private static Set<X509Certificate> getTrustedCerts(KeyStore ks) {
  169 + Set<X509Certificate> set = new HashSet<>();
  170 + try {
  171 + for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) {
  172 + String alias = e.nextElement();
  173 + if (ks.isCertificateEntry(alias)) {
  174 + Certificate cert = ks.getCertificate(alias);
  175 + if (cert instanceof X509Certificate) {
  176 + set.add((X509Certificate)cert);
  177 + }
  178 + } else if (ks.isKeyEntry(alias)) {
  179 + Certificate[] certs = ks.getCertificateChain(alias);
  180 + if ((certs != null) && (certs.length > 0) &&
  181 + (certs[0] instanceof X509Certificate)) {
  182 + set.add((X509Certificate)certs[0]);
  183 + }
  184 + }
  185 + }
  186 + } catch (KeyStoreException ignored) {}
  187 + return Collections.unmodifiableSet(set);
  188 + }
  189 +
  190 +
  191 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.transport.config.ssl;
  17 +
  18 +import lombok.Data;
  19 +import lombok.EqualsAndHashCode;
  20 +import org.thingsboard.server.common.data.ResourceUtils;
  21 +import org.thingsboard.server.common.data.StringUtils;
  22 +
  23 +import java.io.IOException;
  24 +import java.io.InputStream;
  25 +import java.security.GeneralSecurityException;
  26 +import java.security.KeyStore;
  27 +
  28 +@Data
  29 +@EqualsAndHashCode(callSuper = false)
  30 +public class KeystoreSslCredentials extends AbstractSslCredentials {
  31 +
  32 + private String type;
  33 + private String storeFile;
  34 + private String storePassword;
  35 + private String keyPassword;
  36 + private String keyAlias;
  37 +
  38 + @Override
  39 + protected boolean canUse() {
  40 + return ResourceUtils.resourceExists(this, this.storeFile);
  41 + }
  42 +
  43 + @Override
  44 + protected KeyStore loadKeyStore(boolean trustsOnly, char[] keyPasswordArray) throws IOException, GeneralSecurityException {
  45 + String keyStoreType = StringUtils.isEmpty(this.type) ? KeyStore.getDefaultType() : this.type;
  46 + KeyStore keyStore = KeyStore.getInstance(keyStoreType);
  47 + try (InputStream tsFileInputStream = ResourceUtils.getInputStream(this, this.storeFile)) {
  48 + keyStore.load(tsFileInputStream, StringUtils.isEmpty(this.storePassword) ? new char[0] : this.storePassword.toCharArray());
  49 + }
  50 + return keyStore;
  51 + }
  52 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.transport.config.ssl;
  17 +
  18 +import lombok.Data;
  19 +import lombok.EqualsAndHashCode;
  20 +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
  21 +import org.bouncycastle.cert.X509CertificateHolder;
  22 +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
  23 +import org.bouncycastle.jce.provider.BouncyCastleProvider;
  24 +import org.bouncycastle.openssl.PEMDecryptorProvider;
  25 +import org.bouncycastle.openssl.PEMEncryptedKeyPair;
  26 +import org.bouncycastle.openssl.PEMKeyPair;
  27 +import org.bouncycastle.openssl.PEMParser;
  28 +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
  29 +import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
  30 +import org.thingsboard.server.common.data.ResourceUtils;
  31 +import org.thingsboard.server.common.data.StringUtils;
  32 +import java.io.IOException;
  33 +import java.io.InputStream;
  34 +import java.io.InputStreamReader;
  35 +import java.security.GeneralSecurityException;
  36 +import java.security.KeyStore;
  37 +import java.security.PrivateKey;
  38 +import java.security.Security;
  39 +import java.security.cert.CertPath;
  40 +import java.security.cert.Certificate;
  41 +import java.security.cert.CertificateFactory;
  42 +import java.security.cert.X509Certificate;
  43 +import java.util.ArrayList;
  44 +import java.util.List;
  45 +import java.util.stream.Collectors;
  46 +
  47 +@Data
  48 +@EqualsAndHashCode(callSuper = false)
  49 +public class PemSslCredentials extends AbstractSslCredentials {
  50 +
  51 + private String certFile;
  52 + private String keyFile;
  53 + private String keyPassword;
  54 + private final String keyAlias = "serveralias";
  55 +
  56 + @Override
  57 + protected boolean canUse() {
  58 + return ResourceUtils.resourceExists(this, this.certFile);
  59 + }
  60 +
  61 + @Override
  62 + protected KeyStore loadKeyStore(boolean trustsOnly, char[] keyPasswordArray) throws IOException, GeneralSecurityException {
  63 + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
  64 + Security.addProvider(new BouncyCastleProvider());
  65 + }
  66 + List<X509Certificate> certificates = new ArrayList<>();
  67 + PrivateKey privateKey = null;
  68 + JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter();
  69 + JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter();
  70 + try (InputStream inStream = ResourceUtils.getInputStream(this, this.certFile)) {
  71 + try (PEMParser pemParser = new PEMParser(new InputStreamReader(inStream))) {
  72 + Object object;
  73 + while((object = pemParser.readObject()) != null) {
  74 + if (object instanceof X509CertificateHolder) {
  75 + X509Certificate x509Cert = certConverter.getCertificate((X509CertificateHolder) object);
  76 + certificates.add(x509Cert);
  77 + } else if (object instanceof PEMEncryptedKeyPair) {
  78 + PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(keyPasswordArray);
  79 + privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate();
  80 + } else if (object instanceof PEMKeyPair) {
  81 + privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate();
  82 + } else if (object instanceof PrivateKeyInfo) {
  83 + privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object);
  84 + }
  85 + }
  86 + }
  87 + }
  88 + if (privateKey == null && !StringUtils.isEmpty(this.keyFile)) {
  89 + if (ResourceUtils.resourceExists(this, this.keyFile)) {
  90 + try (InputStream inStream = ResourceUtils.getInputStream(this, this.keyFile)) {
  91 + try (PEMParser pemParser = new PEMParser(new InputStreamReader(inStream))) {
  92 + Object object;
  93 + while ((object = pemParser.readObject()) != null) {
  94 + if (object instanceof PEMEncryptedKeyPair) {
  95 + PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(keyPasswordArray);
  96 + privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate();
  97 + break;
  98 + } else if (object instanceof PEMKeyPair) {
  99 + privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate();
  100 + break;
  101 + } else if (object instanceof PrivateKeyInfo) {
  102 + privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object);
  103 + }
  104 + }
  105 + }
  106 + }
  107 + }
  108 + }
  109 + if (certificates.isEmpty()) {
  110 + throw new IllegalArgumentException("No certificates found in certFile: " + this.certFile);
  111 + }
  112 + if (privateKey == null && !trustsOnly) {
  113 + throw new IllegalArgumentException("Unable to load private key neither from certFile: " + this.certFile + " nor from keyFile: " + this.keyFile);
  114 + }
  115 + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
  116 + keyStore.load(null);
  117 + List<Certificate> unique = certificates.stream().distinct().collect(Collectors.toList());
  118 + for (int i = 0; i < unique.size(); i++) {
  119 + keyStore.setCertificateEntry("root-" + i, unique.get(i));
  120 + }
  121 + if (privateKey != null) {
  122 + CertificateFactory factory = CertificateFactory.getInstance("X.509");
  123 + CertPath certPath = factory.generateCertPath(certificates);
  124 + List<? extends Certificate> path = certPath.getCertificates();
  125 + Certificate[] x509Certificates = path.toArray(new Certificate[0]);
  126 + keyStore.setKeyEntry(this.keyAlias, privateKey, keyPasswordArray, x509Certificates);
  127 + }
  128 + return keyStore;
  129 + }
  130 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.transport.config.ssl;
  17 +
  18 +import javax.net.ssl.KeyManagerFactory;
  19 +import javax.net.ssl.TrustManagerFactory;
  20 +import java.io.IOException;
  21 +import java.security.GeneralSecurityException;
  22 +import java.security.KeyStoreException;
  23 +import java.security.NoSuchAlgorithmException;
  24 +import java.security.PrivateKey;
  25 +import java.security.PublicKey;
  26 +import java.security.UnrecoverableKeyException;
  27 +import java.security.cert.X509Certificate;
  28 +
  29 +public interface SslCredentials {
  30 +
  31 + void init(boolean trustsOnly) throws IOException, GeneralSecurityException;
  32 +
  33 + PrivateKey getPrivateKey();
  34 +
  35 + PublicKey getPublicKey();
  36 +
  37 + X509Certificate[] getCertificateChain();
  38 +
  39 + X509Certificate[] getTrustedCertificates();
  40 +
  41 + TrustManagerFactory createTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException;
  42 +
  43 + KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException;
  44 +
  45 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.transport.config.ssl;
  17 +
  18 +import lombok.Data;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +
  21 +import javax.annotation.PostConstruct;
  22 +
  23 +@Slf4j
  24 +@Data
  25 +public class SslCredentialsConfig {
  26 +
  27 + private boolean enabled = true;
  28 + private SslCredentialsType type;
  29 + private PemSslCredentials pem;
  30 + private KeystoreSslCredentials keystore;
  31 +
  32 + private SslCredentials credentials;
  33 +
  34 + private final String name;
  35 + private final boolean trustsOnly;
  36 +
  37 + public SslCredentialsConfig(String name, boolean trustsOnly) {
  38 + this.name = name;
  39 + this.trustsOnly = trustsOnly;
  40 + }
  41 +
  42 + @PostConstruct
  43 + public void init() {
  44 + if (this.enabled) {
  45 + log.info("{}: Initializing SSL credentials.", name);
  46 + if (SslCredentialsType.PEM.equals(type) && pem.canUse()) {
  47 + this.credentials = this.pem;
  48 + } else if (keystore.canUse()) {
  49 + if (SslCredentialsType.PEM.equals(type)) {
  50 + log.warn("{}: Specified PEM configuration is not valid. Using SSL keystore configuration as fallback.", name);
  51 + }
  52 + this.credentials = this.keystore;
  53 + } else {
  54 + throw new RuntimeException(name + ": Invalid SSL credentials configuration. None of the PEM or KEYSTORE configurations can be used!");
  55 + }
  56 + try {
  57 + this.credentials.init(this.trustsOnly);
  58 + } catch (Exception e) {
  59 + throw new RuntimeException(name + ": Failed to init SSL credentials configuration.", e);
  60 + }
  61 + } else {
  62 + log.info("{}: Skipping initialization of disabled SSL credentials.", name);
  63 + }
  64 + }
  65 +
  66 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.transport.config.ssl;
  17 +
  18 +public enum SslCredentialsType {
  19 + PEM,
  20 + KEYSTORE
  21 +}
... ...
... ... @@ -98,17 +98,33 @@ transport:
98 98 bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}"
99 99 # CoAP DTLS bind port
100 100 bind_port: "${COAP_DTLS_BIND_PORT:5684}"
101   - # Path to the key store that holds the certificate
102   - key_store: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
103   - # Password used to access the key store
104   - key_store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
105   - # Password used to access the key
106   - key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
107   - # Key alias
108   - key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
109   - # Skip certificate validity check for client certificates.
110   - skip_validity_check_for_client_cert: "${COAP_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
  101 + # Server DTLS credentials
  102 + credentials:
  103 + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
  104 + type: "${COAP_DTLS_CREDENTIALS_TYPE:PEM}"
  105 + # PEM server credentials
  106 + pem:
  107 + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
  108 + cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}"
  109 + # Path to the server certificate private key file (optional)
  110 + key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}"
  111 + # Server certificate private key password (optional)
  112 + key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}"
  113 + # Keystore server credentials
  114 + keystore:
  115 + # Type of the key store
  116 + type: "${COAP_DTLS_KEY_STORE_TYPE:JKS}"
  117 + # Path to the key store that holds the SSL certificate
  118 + store_file: "${COAP_DTLS_KEY_STORE:coapserver.jks}"
  119 + # Password used to access the key store
  120 + store_password: "${COAP_DTLS_KEY_STORE_PASSWORD:server_ks_password}"
  121 + # Password used to access the key
  122 + key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}"
  123 + # Key alias
  124 + key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}"
111 125 x509:
  126 + # Skip certificate validity check for client certificates.
  127 + skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
112 128 dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}"
113 129 dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}"
114 130 sessions:
... ...
... ... @@ -111,9 +111,33 @@ transport:
111 111 security:
112 112 bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}"
113 113 bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}"
  114 + # Server X509 Certificates support
  115 + credentials:
  116 + # Whether to enable LWM2M server X509 Certificate/RPK support
  117 + enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}"
  118 + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
  119 + type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}"
  120 + # PEM server credentials
  121 + pem:
  122 + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
  123 + cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}"
  124 + # Path to the server certificate private key file (optional)
  125 + key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}"
  126 + # Server certificate private key password (optional)
  127 + key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}"
  128 + # Keystore server credentials
  129 + keystore:
  130 + # Type of the key store
  131 + type: "${LWM2M_SERVER_KEY_STORE_TYPE:JKS}"
  132 + # Path to the key store that holds the SSL certificate
  133 + store_file: "${LWM2M_SERVER_KEY_STORE:lwm2mserver.jks}"
  134 + # Password used to access the key store
  135 + store_password: "${LWM2M_SERVER_KEY_STORE_PASSWORD:server_ks_password}"
  136 + # Password used to access the key
  137 + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_key_password}"
  138 + # Key alias
  139 + key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
114 140 # Only Certificate_x509:
115   - key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}"
116   - key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}"
117 141 skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
118 142 bootstrap:
119 143 enable: "${LWM2M_ENABLED_BS:true}"
... ... @@ -123,18 +147,51 @@ transport:
123 147 security:
124 148 bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}"
125 149 bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}"
126   - # Only Certificate_x509:
127   - key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
128   - key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}"
  150 + # Bootstrap server X509 Certificates support
  151 + credentials:
  152 + # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support
  153 + enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}"
  154 + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
  155 + type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}"
  156 + # PEM server credentials
  157 + pem:
  158 + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
  159 + cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}"
  160 + # Path to the server certificate private key file (optional)
  161 + key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}"
  162 + # Server certificate private key password (optional)
  163 + key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}"
  164 + # Keystore server credentials
  165 + keystore:
  166 + # Type of the key store
  167 + type: "${LWM2M_BS_KEY_STORE_TYPE:JKS}"
  168 + # Path to the key store that holds the SSL certificate
  169 + store_file: "${LWM2M_BS_KEY_STORE:lwm2mserver.jks}"
  170 + # Password used to access the key store
  171 + store_password: "${LWM2M_BS_KEY_STORE_PASSWORD:server_ks_password}"
  172 + # Password used to access the key
  173 + key_password: "${LWM2M_BS_KEY_PASSWORD:server_key_password}"
  174 + # Key alias
  175 + key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}"
129 176 security:
130   - # Certificate_x509:
131   - # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
132   - # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
133   - key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
134   - # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks"
135   - key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}"
136   - key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}"
137   - root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}"
  177 + # X509 trust certificates
  178 + trust-credentials:
  179 + # Whether to load X509 trust certificates
  180 + enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}"
  181 + # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore)
  182 + type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}"
  183 + # PEM certificates
  184 + pem:
  185 + # Path to the certificates file (holds trust certificates)
  186 + cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mserver.pem}"
  187 + # Keystore with trust certificates
  188 + keystore:
  189 + # Type of the key store
  190 + type: "${LWM2M_TRUST_KEY_STORE_TYPE:JKS}"
  191 + # Path to the key store that holds the X509 certificates
  192 + store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mserver.jks}"
  193 + # Password used to access the key store
  194 + store_password: "${LWM2M_TRUST_KEY_STORE_PASSWORD:server_ks_password}"
138 195 recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
139 196 recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
140 197 timeout: "${LWM2M_TIMEOUT:120000}"
... ...
... ... @@ -106,14 +106,28 @@ transport:
106 106 bind_port: "${MQTT_SSL_BIND_PORT:8883}"
107 107 # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext
108 108 protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}"
109   - # Path to the key store that holds the SSL certificate
110   - key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
111   - # Password used to access the key store
112   - key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
113   - # Password used to access the key
114   - key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
115   - # Type of the key store
116   - key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
  109 + # Server SSL credentials
  110 + credentials:
  111 + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore)
  112 + type: "${MQTT_SSL_CREDENTIALS_TYPE:PEM}"
  113 + # PEM server credentials
  114 + pem:
  115 + # Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
  116 + cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}"
  117 + # Path to the server certificate private key file (optional)
  118 + key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}"
  119 + # Server certificate private key password (optional)
  120 + key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}"
  121 + # Keystore server credentials
  122 + keystore:
  123 + # Type of the key store
  124 + type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
  125 + # Path to the key store that holds the SSL certificate
  126 + store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
  127 + # Password used to access the key store
  128 + store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
  129 + # Password used to access the key
  130 + key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
117 131 # Skip certificate validity check for client certificates.
118 132 skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
119 133 sessions:
... ...