Showing
21 changed files
with
883 additions
and
239 deletions
@@ -22,28 +22,11 @@ import org.eclipse.leshan.core.util.Hex; | @@ -22,28 +22,11 @@ import org.eclipse.leshan.core.util.Hex; | ||
22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
23 | import org.springframework.stereotype.Service; | 23 | import org.springframework.stereotype.Service; |
24 | import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; | 24 | import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; |
25 | +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; | ||
25 | import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; | 26 | import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; |
26 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; | 27 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; |
27 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; | 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 | @Slf4j | 30 | @Slf4j |
48 | @Service | 31 | @Service |
49 | @RequiredArgsConstructor | 32 | @RequiredArgsConstructor |
@@ -72,10 +55,9 @@ public class LwM2MServerSecurityInfoRepository { | @@ -72,10 +55,9 @@ public class LwM2MServerSecurityInfoRepository { | ||
72 | 55 | ||
73 | private String getPublicKey(LwM2MSecureServerConfig config) { | 56 | private String getPublicKey(LwM2MSecureServerConfig config) { |
74 | try { | 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 | } catch (Exception e) { | 62 | } catch (Exception e) { |
81 | log.trace("Failed to fetch public key from key store!", e); | 63 | log.trace("Failed to fetch public key from key store!", e); |
@@ -619,14 +619,28 @@ transport: | @@ -619,14 +619,28 @@ transport: | ||
619 | bind_port: "${MQTT_SSL_BIND_PORT:8883}" | 619 | bind_port: "${MQTT_SSL_BIND_PORT:8883}" |
620 | # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext | 620 | # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext |
621 | protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}" | 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 | # Skip certificate validity check for client certificates. | 644 | # Skip certificate validity check for client certificates. |
631 | skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" | 645 | skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" |
632 | # Local CoAP transport parameters | 646 | # Local CoAP transport parameters |
@@ -645,14 +659,30 @@ transport: | @@ -645,14 +659,30 @@ transport: | ||
645 | bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" | 659 | bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" |
646 | # CoAP DTLS bind port | 660 | # CoAP DTLS bind port |
647 | bind_port: "${COAP_DTLS_BIND_PORT:5684}" | 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 | x509: | 686 | x509: |
657 | # Skip certificate validity check for client certificates. | 687 | # Skip certificate validity check for client certificates. |
658 | skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" | 688 | skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" |
@@ -669,9 +699,33 @@ transport: | @@ -669,9 +699,33 @@ transport: | ||
669 | security: | 699 | security: |
670 | bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" | 700 | bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" |
671 | bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}" | 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 | # Only Certificate_x509: | 728 | # Only Certificate_x509: |
673 | - key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" | ||
674 | - key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}" | ||
675 | skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" | 729 | skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" |
676 | bootstrap: | 730 | bootstrap: |
677 | enable: "${LWM2M_ENABLED_BS:true}" | 731 | enable: "${LWM2M_ENABLED_BS:true}" |
@@ -681,18 +735,51 @@ transport: | @@ -681,18 +735,51 @@ transport: | ||
681 | security: | 735 | security: |
682 | bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" | 736 | bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" |
683 | bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}" | 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 | security: | 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 | recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" | 783 | recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" |
697 | recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" | 784 | recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" |
698 | timeout: "${LWM2M_TIMEOUT:120000}" | 785 | timeout: "${LWM2M_TIMEOUT:120000}" |
@@ -20,11 +20,16 @@ import org.eclipse.californium.elements.util.SslContextUtil; | @@ -20,11 +20,16 @@ import org.eclipse.californium.elements.util.SslContextUtil; | ||
20 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; | 20 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; |
21 | import org.eclipse.californium.scandium.dtls.CertificateType; | 21 | import org.eclipse.californium.scandium.dtls.CertificateType; |
22 | import org.springframework.beans.factory.annotation.Autowired; | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | +import org.springframework.beans.factory.annotation.Qualifier; | ||
23 | import org.springframework.beans.factory.annotation.Value; | 24 | import org.springframework.beans.factory.annotation.Value; |
24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
26 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
27 | +import org.springframework.context.annotation.Bean; | ||
25 | import org.springframework.stereotype.Component; | 28 | import org.springframework.stereotype.Component; |
26 | import org.thingsboard.server.common.data.ResourceUtils; | 29 | import org.thingsboard.server.common.data.ResourceUtils; |
27 | import org.thingsboard.server.common.transport.TransportService; | 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 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | 33 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
29 | 34 | ||
30 | import java.io.IOException; | 35 | import java.io.IOException; |
@@ -45,17 +50,15 @@ public class TbCoapDtlsSettings { | @@ -45,17 +50,15 @@ public class TbCoapDtlsSettings { | ||
45 | @Value("${transport.coap.dtls.bind_port}") | 50 | @Value("${transport.coap.dtls.bind_port}") |
46 | private Integer port; | 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 | @Value("${transport.coap.dtls.x509.skip_validity_check_for_client_cert:false}") | 63 | @Value("${transport.coap.dtls.x509.skip_validity_check_for_client_cert:false}") |
61 | private boolean skipValidityCheckForClientCert; | 64 | private boolean skipValidityCheckForClientCert; |
@@ -75,8 +78,9 @@ public class TbCoapDtlsSettings { | @@ -75,8 +78,9 @@ public class TbCoapDtlsSettings { | ||
75 | public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException { | 78 | public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException { |
76 | DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(); | 79 | DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(); |
77 | configBuilder.setAddress(getInetSocketAddress()); | 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 | configBuilder.setServerOnly(true); | 84 | configBuilder.setServerOnly(true); |
81 | configBuilder.setClientAuthenticationRequired(false); | 85 | configBuilder.setClientAuthenticationRequired(false); |
82 | configBuilder.setClientAuthenticationWanted(true); | 86 | configBuilder.setClientAuthenticationWanted(true); |
@@ -94,15 +98,6 @@ public class TbCoapDtlsSettings { | @@ -94,15 +98,6 @@ public class TbCoapDtlsSettings { | ||
94 | return configBuilder.build(); | 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 | private InetSocketAddress getInetSocketAddress() throws UnknownHostException { | 101 | private InetSocketAddress getInetSocketAddress() throws UnknownHostException { |
107 | InetAddress addr = InetAddress.getByName(host); | 102 | InetAddress addr = InetAddress.getByName(host); |
108 | return new InetSocketAddress(addr, port); | 103 | return new InetSocketAddress(addr, port); |
@@ -27,6 +27,30 @@ import java.net.URL; | @@ -27,6 +27,30 @@ import java.net.URL; | ||
27 | @Slf4j | 27 | @Slf4j |
28 | public class ResourceUtils { | 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 | public static InputStream getInputStream(Object classLoaderSource, String filePath) { | 54 | public static InputStream getInputStream(Object classLoaderSource, String filePath) { |
31 | return getInputStream(classLoaderSource.getClass().getClassLoader(), filePath); | 55 | return getInputStream(classLoaderSource.getClass().getClassLoader(), filePath); |
32 | } | 56 | } |
@@ -27,6 +27,7 @@ import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; | @@ -27,6 +27,7 @@ import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; | ||
27 | import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; | 27 | import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; |
28 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 28 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
29 | import org.springframework.stereotype.Component; | 29 | import org.springframework.stereotype.Component; |
30 | +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; | ||
30 | import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; | 31 | import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; |
31 | import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; | 32 | import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; |
32 | import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigurationAdapter; | 33 | import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigurationAdapter; |
@@ -114,49 +115,22 @@ public class LwM2MTransportBootstrapService { | @@ -114,49 +115,22 @@ public class LwM2MTransportBootstrapService { | ||
114 | } | 115 | } |
115 | 116 | ||
116 | private void setServerWithCredentials(LeshanBootstrapServerBuilder builder) { | 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 | } else { | 125 | } else { |
132 | /* by default trust all */ | 126 | /* by default trust all */ |
133 | builder.setTrustedCertificates(new X509Certificate[0]); | 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,6 +15,8 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.transport.lwm2m.config; | 16 | package org.thingsboard.server.transport.lwm2m.config; |
17 | 17 | ||
18 | +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; | ||
19 | + | ||
18 | public interface LwM2MSecureServerConfig { | 20 | public interface LwM2MSecureServerConfig { |
19 | 21 | ||
20 | Integer getId(); | 22 | Integer getId(); |
@@ -27,8 +29,6 @@ public interface LwM2MSecureServerConfig { | @@ -27,8 +29,6 @@ public interface LwM2MSecureServerConfig { | ||
27 | 29 | ||
28 | Integer getSecurePort(); | 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,9 +17,15 @@ package org.thingsboard.server.transport.lwm2m.config; | ||
17 | 17 | ||
18 | import lombok.Getter; | 18 | import lombok.Getter; |
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | +import org.springframework.beans.factory.annotation.Autowired; | ||
21 | +import org.springframework.beans.factory.annotation.Qualifier; | ||
20 | import org.springframework.beans.factory.annotation.Value; | 22 | import org.springframework.beans.factory.annotation.Value; |
21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
24 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
25 | +import org.springframework.context.annotation.Bean; | ||
22 | import org.springframework.stereotype.Component; | 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 | @Slf4j | 30 | @Slf4j |
25 | @Component | 31 | @Component |
@@ -46,12 +52,18 @@ public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig { | @@ -46,12 +52,18 @@ public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig { | ||
46 | @Value("${transport.lwm2m.bootstrap.security.bind_port:}") | 52 | @Value("${transport.lwm2m.bootstrap.security.bind_port:}") |
47 | private Integer securePort; | 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,10 +18,16 @@ package org.thingsboard.server.transport.lwm2m.config; | ||
18 | import lombok.Getter; | 18 | import lombok.Getter; |
19 | import lombok.Setter; | 19 | import lombok.Setter; |
20 | import lombok.extern.slf4j.Slf4j; | 20 | import lombok.extern.slf4j.Slf4j; |
21 | +import org.springframework.beans.factory.annotation.Autowired; | ||
22 | +import org.springframework.beans.factory.annotation.Qualifier; | ||
21 | import org.springframework.beans.factory.annotation.Value; | 23 | import org.springframework.beans.factory.annotation.Value; |
22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
25 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
26 | +import org.springframework.context.annotation.Bean; | ||
23 | import org.springframework.stereotype.Component; | 27 | import org.springframework.stereotype.Component; |
24 | import org.thingsboard.server.common.data.ResourceUtils; | 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 | import javax.annotation.PostConstruct; | 32 | import javax.annotation.PostConstruct; |
27 | import java.io.InputStream; | 33 | import java.io.InputStream; |
@@ -65,26 +71,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { | @@ -65,26 +71,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { | ||
65 | private int cleanPeriodInSec; | 71 | private int cleanPeriodInSec; |
66 | 72 | ||
67 | @Getter | 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 | @Value("${transport.lwm2m.server.id:}") | 74 | @Value("${transport.lwm2m.server.id:}") |
89 | private Integer id; | 75 | private Integer id; |
90 | 76 | ||
@@ -105,14 +91,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { | @@ -105,14 +91,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { | ||
105 | private Integer securePort; | 91 | private Integer securePort; |
106 | 92 | ||
107 | @Getter | 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 | @Value("${transport.lwm2m.log_max_length:}") | 94 | @Value("${transport.lwm2m.log_max_length:}") |
117 | private int logMaxLength; | 95 | private int logMaxLength; |
118 | 96 | ||
@@ -124,15 +102,32 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { | @@ -124,15 +102,32 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { | ||
124 | @Value("${transport.lwm2m.paging_transmission_window:10000}") | 102 | @Value("${transport.lwm2m.paging_transmission_window:10000}") |
125 | private long pagingTransmissionWindow; | 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,12 +87,8 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer | ||
87 | try { | 87 | try { |
88 | /* by default trust all */ | 88 | /* by default trust all */ |
89 | X509Certificate[] trustedCertificates = new X509Certificate[0]; | 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 | staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates); | 93 | staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates); |
98 | } catch (Exception e) { | 94 | } catch (Exception e) { |
@@ -29,6 +29,7 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider; | @@ -29,6 +29,7 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider; | ||
29 | import org.springframework.stereotype.Component; | 29 | import org.springframework.stereotype.Component; |
30 | import org.thingsboard.server.cache.ota.OtaPackageDataCache; | 30 | import org.thingsboard.server.cache.ota.OtaPackageDataCache; |
31 | import org.thingsboard.server.common.data.DataConstants; | 31 | import org.thingsboard.server.common.data.DataConstants; |
32 | +import org.thingsboard.server.common.transport.config.ssl.SslCredentials; | ||
32 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; | 33 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
33 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; | 34 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; |
34 | import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; | 35 | import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; |
@@ -141,7 +142,11 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { | @@ -141,7 +142,11 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { | ||
141 | } | 142 | } |
142 | 143 | ||
143 | private void setServerWithCredentials(LeshanServerBuilder builder, DtlsConnectorConfig.Builder dtlsConfig) { | 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 | dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); | 150 | dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); |
146 | builder.setAuthorizer(authorizer); | 151 | builder.setAuthorizer(authorizer); |
147 | dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); | 152 | dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); |
@@ -153,26 +158,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { | @@ -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 | @Override | 161 | @Override |
177 | public String getName() { | 162 | public String getName() { |
178 | return DataConstants.LWM2M_TRANSPORT_NAME; | 163 | return DataConstants.LWM2M_TRANSPORT_NAME; |
@@ -18,16 +18,20 @@ package org.thingsboard.server.transport.mqtt; | @@ -18,16 +18,20 @@ package org.thingsboard.server.transport.mqtt; | ||
18 | import io.netty.handler.ssl.SslHandler; | 18 | import io.netty.handler.ssl.SslHandler; |
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | import org.springframework.beans.factory.annotation.Autowired; | 20 | import org.springframework.beans.factory.annotation.Autowired; |
21 | +import org.springframework.beans.factory.annotation.Qualifier; | ||
21 | import org.springframework.beans.factory.annotation.Value; | 22 | import org.springframework.beans.factory.annotation.Value; |
22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
24 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
25 | +import org.springframework.context.annotation.Bean; | ||
23 | import org.springframework.stereotype.Component; | 26 | import org.springframework.stereotype.Component; |
24 | import org.springframework.util.StringUtils; | 27 | import org.springframework.util.StringUtils; |
25 | import org.thingsboard.server.common.data.DeviceTransportType; | 28 | import org.thingsboard.server.common.data.DeviceTransportType; |
26 | -import org.thingsboard.server.common.data.ResourceUtils; | ||
27 | import org.thingsboard.server.common.msg.EncryptionUtil; | 29 | import org.thingsboard.server.common.msg.EncryptionUtil; |
28 | import org.thingsboard.server.common.transport.TransportService; | 30 | import org.thingsboard.server.common.transport.TransportService; |
29 | import org.thingsboard.server.common.transport.TransportServiceCallback; | 31 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
30 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | 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 | import org.thingsboard.server.common.transport.util.SslUtil; | 35 | import org.thingsboard.server.common.transport.util.SslUtil; |
32 | import org.thingsboard.server.gen.transport.TransportProtos; | 36 | import org.thingsboard.server.gen.transport.TransportProtos; |
33 | 37 | ||
@@ -38,8 +42,6 @@ import javax.net.ssl.SSLEngine; | @@ -38,8 +42,6 @@ import javax.net.ssl.SSLEngine; | ||
38 | import javax.net.ssl.TrustManager; | 42 | import javax.net.ssl.TrustManager; |
39 | import javax.net.ssl.TrustManagerFactory; | 43 | import javax.net.ssl.TrustManagerFactory; |
40 | import javax.net.ssl.X509TrustManager; | 44 | import javax.net.ssl.X509TrustManager; |
41 | -import java.io.InputStream; | ||
42 | -import java.security.KeyStore; | ||
43 | import java.security.cert.CertificateEncodingException; | 45 | import java.security.cert.CertificateEncodingException; |
44 | import java.security.cert.CertificateException; | 46 | import java.security.cert.CertificateException; |
45 | import java.security.cert.X509Certificate; | 47 | import java.security.cert.X509Certificate; |
@@ -56,18 +58,20 @@ public class MqttSslHandlerProvider { | @@ -56,18 +58,20 @@ public class MqttSslHandlerProvider { | ||
56 | 58 | ||
57 | @Value("${transport.mqtt.ssl.protocol}") | 59 | @Value("${transport.mqtt.ssl.protocol}") |
58 | private String sslProtocol; | 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 | @Autowired | 62 | @Autowired |
69 | private TransportService transportService; | 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 | private SSLContext sslContext; | 75 | private SSLContext sslContext; |
72 | 76 | ||
73 | public SslHandler getSslHandler() { | 77 | public SslHandler getSslHandler() { |
@@ -86,19 +90,9 @@ public class MqttSslHandlerProvider { | @@ -86,19 +90,9 @@ public class MqttSslHandlerProvider { | ||
86 | 90 | ||
87 | private SSLContext createSslContext() { | 91 | private SSLContext createSslContext() { |
88 | try { | 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 | KeyManager[] km = kmf.getKeyManagers(); | 97 | KeyManager[] km = kmf.getKeyManagers(); |
104 | TrustManager x509wrapped = getX509TrustManager(tmFactory); | 98 | TrustManager x509wrapped = getX509TrustManager(tmFactory); |
@@ -129,6 +129,14 @@ | @@ -129,6 +129,14 @@ | ||
129 | <groupId>org.eclipse.leshan</groupId> | 129 | <groupId>org.eclipse.leshan</groupId> |
130 | <artifactId>leshan-server-cf</artifactId> | 130 | <artifactId>leshan-server-cf</artifactId> |
131 | </dependency> | 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 | </dependencies> | 140 | </dependencies> |
133 | 141 | ||
134 | <build> | 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,17 +98,33 @@ transport: | ||
98 | bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" | 98 | bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" |
99 | # CoAP DTLS bind port | 99 | # CoAP DTLS bind port |
100 | bind_port: "${COAP_DTLS_BIND_PORT:5684}" | 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 | x509: | 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 | dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}" | 128 | dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}" |
113 | dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}" | 129 | dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}" |
114 | sessions: | 130 | sessions: |
@@ -111,9 +111,33 @@ transport: | @@ -111,9 +111,33 @@ transport: | ||
111 | security: | 111 | security: |
112 | bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" | 112 | bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" |
113 | bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}" | 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 | # Only Certificate_x509: | 140 | # Only Certificate_x509: |
115 | - key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" | ||
116 | - key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}" | ||
117 | skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" | 141 | skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" |
118 | bootstrap: | 142 | bootstrap: |
119 | enable: "${LWM2M_ENABLED_BS:true}" | 143 | enable: "${LWM2M_ENABLED_BS:true}" |
@@ -123,18 +147,51 @@ transport: | @@ -123,18 +147,51 @@ transport: | ||
123 | security: | 147 | security: |
124 | bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" | 148 | bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" |
125 | bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}" | 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 | security: | 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 | recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" | 195 | recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" |
139 | recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" | 196 | recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" |
140 | timeout: "${LWM2M_TIMEOUT:120000}" | 197 | timeout: "${LWM2M_TIMEOUT:120000}" |
@@ -106,14 +106,28 @@ transport: | @@ -106,14 +106,28 @@ transport: | ||
106 | bind_port: "${MQTT_SSL_BIND_PORT:8883}" | 106 | bind_port: "${MQTT_SSL_BIND_PORT:8883}" |
107 | # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext | 107 | # SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext |
108 | protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}" | 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 | # Skip certificate validity check for client certificates. | 131 | # Skip certificate validity check for client certificates. |
118 | skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" | 132 | skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" |
119 | sessions: | 133 | sessions: |