Showing
12 changed files
with
173 additions
and
515 deletions
... | ... | @@ -30,8 +30,12 @@ import java.math.BigInteger; |
30 | 30 | import java.security.AlgorithmParameters; |
31 | 31 | import java.security.GeneralSecurityException; |
32 | 32 | import java.security.KeyFactory; |
33 | +import java.security.KeyStore; | |
33 | 34 | import java.security.KeyStoreException; |
35 | +import java.security.NoSuchAlgorithmException; | |
36 | +import java.security.PrivateKey; | |
34 | 37 | import java.security.PublicKey; |
38 | +import java.security.UnrecoverableKeyException; | |
35 | 39 | import java.security.cert.CertificateEncodingException; |
36 | 40 | import java.security.cert.X509Certificate; |
37 | 41 | import java.security.spec.ECGenParameterSpec; |
... | ... | @@ -62,49 +66,23 @@ public class LwM2MServerSecurityInfoRepository { |
62 | 66 | bsServ.setPort(serverConfig.getPort()); |
63 | 67 | bsServ.setSecurityHost(serverConfig.getSecureHost()); |
64 | 68 | bsServ.setSecurityPort(serverConfig.getSecurePort()); |
65 | - bsServ.setServerPublicKey(getPublicKey(serverConfig.getCertificateAlias(), this.serverConfig.getPublicX(), this.serverConfig.getPublicY())); | |
69 | + bsServ.setServerPublicKey(getPublicKey(serverConfig)); | |
66 | 70 | return bsServ; |
67 | 71 | } |
68 | 72 | |
69 | - private String getPublicKey(String alias, String publicServerX, String publicServerY) { | |
70 | - String publicKey = getServerPublicKeyX509(alias); | |
71 | - return publicKey != null ? publicKey : getRPKPublicKey(publicServerX, publicServerY); | |
72 | - } | |
73 | - | |
74 | - private String getServerPublicKeyX509(String alias) { | |
75 | - try { | |
76 | - X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(alias); | |
77 | - return Hex.encodeHexString(serverCertificate.getEncoded()); | |
78 | - } catch (CertificateEncodingException | KeyStoreException e) { | |
79 | - e.printStackTrace(); | |
80 | - } | |
81 | - return null; | |
82 | - } | |
83 | - | |
84 | - private String getRPKPublicKey(String publicServerX, String publicServerY) { | |
73 | + private String getPublicKey(LwM2MSecureServerConfig config) { | |
85 | 74 | try { |
86 | - /** Get Elliptic Curve Parameter spec for secp256r1 */ | |
87 | - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); | |
88 | - algoParameters.init(new ECGenParameterSpec("secp256r1")); | |
89 | - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); | |
90 | - if (publicServerX != null && !publicServerX.isEmpty() && publicServerY != null && !publicServerY.isEmpty()) { | |
91 | - /** Get point values */ | |
92 | - byte[] publicX = Hex.decodeHex(publicServerX.toCharArray()); | |
93 | - byte[] publicY = Hex.decodeHex(publicServerY.toCharArray()); | |
94 | - /** Create key specs */ | |
95 | - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), | |
96 | - parameterSpec); | |
97 | - /** Get keys */ | |
98 | - PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); | |
99 | - if (publicKey != null && publicKey.getEncoded().length > 0) { | |
100 | - return Hex.encodeHexString(publicKey.getEncoded()); | |
101 | - } | |
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()); | |
102 | 79 | } |
103 | - } catch (GeneralSecurityException | IllegalArgumentException e) { | |
104 | - log.error("[{}] Failed generate Server RPK for profile", e.getMessage()); | |
105 | - throw new RuntimeException(e); | |
80 | + } catch (Exception e) { | |
81 | + log.trace("Failed to fetch public key from key store!", e); | |
82 | + | |
106 | 83 | } |
107 | - return null; | |
84 | + return ""; | |
108 | 85 | } |
86 | + | |
109 | 87 | } |
110 | 88 | ... | ... |
... | ... | @@ -647,48 +647,40 @@ transport: |
647 | 647 | bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" |
648 | 648 | bind_port: "${LWM2M_BIND_PORT:5685}" |
649 | 649 | security: |
650 | - bind_address: "${LWM2M_BIND_ADDRESS_SECURITY:0.0.0.0}" | |
651 | - bind_port: "${LWM2M_BIND_PORT_SECURITY:5686}" | |
652 | - # Only for RPK: Public & Private Key. If the keystore file is missing or not working | |
653 | - public_x: "${LWM2M_SERVER_PUBLIC_X:05064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f358}" | |
654 | - public_y: "${LWM2M_SERVER_PUBLIC_Y:5eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}" | |
655 | - private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}" | |
650 | + bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" | |
651 | + bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}" | |
656 | 652 | # Only Certificate_x509: |
657 | - alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}" | |
653 | + key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" | |
654 | + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}" | |
658 | 655 | skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" |
659 | 656 | bootstrap: |
660 | 657 | enable: "${LWM2M_ENABLED_BS:true}" |
661 | 658 | id: "${LWM2M_SERVER_ID_BS:111}" |
662 | - bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" | |
663 | - bind_port: "${LWM2M_BIND_PORT_BS:5687}" | |
659 | + bind_address: "${LWM2M_BS_BIND_ADDRESS:0.0.0.0}" | |
660 | + bind_port: "${LWM2M_BS_BIND_PORT:5687}" | |
664 | 661 | security: |
665 | - bind_address: "${LWM2M_BIND_ADDRESS_SECURITY_BS:0.0.0.0}" | |
666 | - bind_port: "${LWM2M_BIND_PORT_SECURITY_BS:5688}" | |
667 | - # Only for RPK: Public & Private Key. If the keystore file is missing or not working | |
668 | - public_x: "${LWM2M_SERVER_PUBLIC_X_BS:5017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f91}" | |
669 | - public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:3fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" | |
670 | - private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" | |
662 | + bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" | |
663 | + bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}" | |
671 | 664 | # Only Certificate_x509: |
672 | - alias: "${LWM2M_KEYSTORE_ALIAS_BS:bootstrap}" | |
665 | + key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}" | |
666 | + key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}" | |
673 | 667 | security: |
674 | 668 | # Certificate_x509: |
675 | 669 | # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format |
676 | 670 | # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh |
677 | 671 | key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}" |
678 | 672 | # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks" |
679 | - key_store: "${LWM2M_KEY_STORE:lwm2mserver.jks}" | |
680 | - key_store_password: "${LWM2M_KEY_STORE_PASSWORD:server_ks_password}" | |
681 | - root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}" | |
682 | - enable_gen_new_key_psk_rpk: "${ENABLE_GEN_NEW_KEY_PSK_RPK:false}" | |
673 | + key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}" | |
674 | + key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}" | |
675 | + root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}" | |
676 | + recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" | |
677 | + recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" | |
683 | 678 | timeout: "${LWM2M_TIMEOUT:120000}" |
684 | - recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" | |
685 | - recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" | |
686 | 679 | uplink_pool_size: "${LWM2M_UPLINK_POOL_SIZE:10}" |
687 | 680 | downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}" |
688 | 681 | ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" |
689 | - registration_store_pool_size: "${LWM2M_REGISTRATION_STORE_POOL_SIZE:100}" | |
690 | 682 | clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" |
691 | - log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}" | |
683 | + log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" | |
692 | 684 | # Use redis for Security and Registration stores |
693 | 685 | redis.enabled: "${LWM2M_REDIS_ENABLED:false}" |
694 | 686 | snmp: | ... | ... |
1 | 1 | transport.lwm2m.security.key_store=lwm2m/credentials/serverKeyStore.jks |
2 | 2 | transport.lwm2m.security.key_store_password=server |
3 | 3 | edges.enabled=true |
4 | -transport.lwm2m.bootstrap.security.alias=server | |
\ No newline at end of file | ||
4 | +transport.lwm2m.server.security.key_alias=server | |
5 | +transport.lwm2m.server.security.key_password=server | |
6 | +transport.lwm2m.bootstrap.security.key_alias=server | |
7 | +transport.lwm2m.bootstrap.security.key_password=server | |
\ No newline at end of file | ... | ... |
... | ... | @@ -19,57 +19,33 @@ import lombok.RequiredArgsConstructor; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | 20 | import org.eclipse.californium.elements.util.SslContextUtil; |
21 | 21 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; |
22 | -import org.eclipse.leshan.core.util.Hex; | |
23 | 22 | import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; |
24 | 23 | import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; |
25 | 24 | import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; |
26 | 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
27 | 26 | import org.springframework.stereotype.Component; |
28 | -import org.thingsboard.server.common.data.StringUtils; | |
29 | 27 | import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; |
30 | 28 | import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; |
31 | 29 | import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; |
32 | 30 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; |
33 | 31 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; |
34 | -import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; | |
32 | +import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService; | |
35 | 33 | |
36 | 34 | import javax.annotation.PostConstruct; |
37 | 35 | import javax.annotation.PreDestroy; |
38 | -import java.math.BigInteger; | |
39 | -import java.security.AlgorithmParameters; | |
40 | -import java.security.KeyFactory; | |
41 | 36 | import java.security.KeyStore; |
42 | 37 | import java.security.KeyStoreException; |
43 | -import java.security.NoSuchAlgorithmException; | |
44 | 38 | import java.security.PrivateKey; |
45 | 39 | import java.security.PublicKey; |
46 | -import java.security.cert.CertificateEncodingException; | |
47 | 40 | import java.security.cert.X509Certificate; |
48 | -import java.security.interfaces.ECPublicKey; | |
49 | -import java.security.spec.ECGenParameterSpec; | |
50 | -import java.security.spec.ECParameterSpec; | |
51 | -import java.security.spec.ECPoint; | |
52 | -import java.security.spec.ECPublicKeySpec; | |
53 | -import java.security.spec.InvalidKeySpecException; | |
54 | -import java.security.spec.InvalidParameterSpecException; | |
55 | -import java.security.spec.KeySpec; | |
56 | -import java.security.spec.PKCS8EncodedKeySpec; | |
57 | -import java.util.Arrays; | |
58 | 41 | |
59 | -import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; | |
60 | -import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; | |
61 | -import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; | |
62 | -import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; | |
63 | 42 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; |
64 | 43 | |
65 | 44 | @Slf4j |
66 | 45 | @Component |
67 | 46 | @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true')") |
68 | 47 | @RequiredArgsConstructor |
69 | -//TODO: @ybondarenko please refactor this to be similar to DefaultLwM2mTransportService | |
70 | 48 | public class LwM2MTransportBootstrapService { |
71 | - private PublicKey publicKey; | |
72 | - private PrivateKey privateKey; | |
73 | 49 | private boolean pskMode = false; |
74 | 50 | |
75 | 51 | private final LwM2MTransportServerConfig serverConfig; |
... | ... | @@ -81,9 +57,6 @@ public class LwM2MTransportBootstrapService { |
81 | 57 | |
82 | 58 | @PostConstruct |
83 | 59 | public void init() { |
84 | - if (serverConfig.getEnableGenNewKeyPskRpk()) { | |
85 | - new LWM2MGenerationPSkRPkECC(); | |
86 | - } | |
87 | 60 | log.info("Starting LwM2M transport bootstrap server..."); |
88 | 61 | this.server = getLhBootstrapServer(); |
89 | 62 | this.server.start(); |
... | ... | @@ -102,44 +75,34 @@ public class LwM2MTransportBootstrapService { |
102 | 75 | builder.setLocalAddress(bootstrapConfig.getHost(), bootstrapConfig.getPort()); |
103 | 76 | builder.setLocalSecureAddress(bootstrapConfig.getSecureHost(), bootstrapConfig.getSecurePort()); |
104 | 77 | |
105 | - /** Create CoAP Config */ | |
78 | + /* Create CoAP Config */ | |
106 | 79 | builder.setCoapConfig(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig)); |
107 | 80 | |
108 | - /** Define model provider (Create Models )*/ | |
81 | + /* Define model provider (Create Models )*/ | |
109 | 82 | |
110 | - /** Create credentials */ | |
83 | + /* Create credentials */ | |
111 | 84 | this.setServerWithCredentials(builder); |
112 | 85 | |
113 | 86 | // /** Set securityStore with new ConfigStore */ |
114 | 87 | // builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore); |
115 | 88 | |
116 | - /** SecurityStore */ | |
89 | + /* SecurityStore */ | |
117 | 90 | builder.setSecurityStore(lwM2MBootstrapSecurityStore); |
118 | 91 | |
119 | 92 | |
120 | - /** Create and Set DTLS Config */ | |
93 | + /* Create and Set DTLS Config */ | |
121 | 94 | DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); |
122 | 95 | dtlsConfig.setRecommendedSupportedGroupsOnly(serverConfig.isRecommendedSupportedGroups()); |
123 | 96 | dtlsConfig.setRecommendedCipherSuitesOnly(serverConfig.isRecommendedCiphers()); |
124 | - if (this.pskMode) { | |
125 | - dtlsConfig.setSupportedCipherSuites( | |
126 | - TLS_PSK_WITH_AES_128_CCM_8, | |
127 | - TLS_PSK_WITH_AES_128_CBC_SHA256); | |
128 | - } else { | |
129 | - dtlsConfig.setSupportedCipherSuites( | |
130 | - TLS_PSK_WITH_AES_128_CCM_8, | |
131 | - TLS_PSK_WITH_AES_128_CBC_SHA256, | |
132 | - TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, | |
133 | - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256); | |
134 | - } | |
97 | + dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES); | |
135 | 98 | |
136 | - /** Set DTLS Config */ | |
99 | + /* Set DTLS Config */ | |
137 | 100 | builder.setDtlsConfig(dtlsConfig); |
138 | 101 | |
139 | 102 | BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore); |
140 | 103 | builder.setSessionManager(sessionManager); |
141 | 104 | |
142 | - /** Create BootstrapServer */ | |
105 | + /* Create BootstrapServer */ | |
143 | 106 | return builder.build(); |
144 | 107 | } |
145 | 108 | |
... | ... | @@ -154,19 +117,15 @@ public class LwM2MTransportBootstrapService { |
154 | 117 | trustedCertificates[0] = rootCAX509Cert; |
155 | 118 | builder.setTrustedCertificates(trustedCertificates); |
156 | 119 | } else { |
157 | - /** by default trust all */ | |
120 | + /* by default trust all */ | |
158 | 121 | builder.setTrustedCertificates(new X509Certificate[0]); |
159 | 122 | } |
160 | 123 | } |
161 | - } else if (this.setServerRPK(builder)) { | |
162 | - this.infoPramsUri("RPK"); | |
163 | - this.infoParamsBootstrapServerKey(this.publicKey, this.privateKey); | |
164 | 124 | } else { |
165 | - /** by default trust all */ | |
125 | + /* by default trust all */ | |
166 | 126 | builder.setTrustedCertificates(new X509Certificate[0]); |
167 | 127 | log.info("Unable to load X509 files for BootStrapServer"); |
168 | 128 | this.pskMode = true; |
169 | - this.infoPramsUri("PSK"); | |
170 | 129 | } |
171 | 130 | } catch (KeyStoreException ex) { |
172 | 131 | log.error("[{}] Unable to load X509 files server", ex.getMessage()); |
... | ... | @@ -174,20 +133,15 @@ public class LwM2MTransportBootstrapService { |
174 | 133 | } |
175 | 134 | |
176 | 135 | private boolean setBuilderX509(LeshanBootstrapServerBuilder builder) { |
177 | - /** | |
178 | - * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE | |
179 | - * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks | |
180 | - */ | |
181 | 136 | try { |
182 | 137 | X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(serverConfig.getKeyStoreValue().getCertificateChain(this.bootstrapConfig.getCertificateAlias())); |
183 | 138 | X509Certificate serverCertificate = certificateChain[0]; |
184 | - PrivateKey privateKey = (PrivateKey) serverConfig.getKeyStoreValue().getKey(this.bootstrapConfig.getCertificateAlias(), serverConfig.getKeyStorePassword() == null ? null : serverConfig.getKeyStorePassword().toCharArray()); | |
139 | + PrivateKey privateKey = (PrivateKey) serverConfig.getKeyStoreValue().getKey(this.bootstrapConfig.getCertificateAlias(), serverConfig.getCertificatePassword() == null ? null : serverConfig.getCertificatePassword().toCharArray()); | |
185 | 140 | PublicKey publicKey = serverCertificate.getPublicKey(); |
186 | 141 | if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) { |
187 | 142 | builder.setPublicKey(serverCertificate.getPublicKey()); |
188 | 143 | builder.setPrivateKey(privateKey); |
189 | 144 | builder.setCertificateChain(certificateChain); |
190 | - this.infoParamsServerX509(serverCertificate, publicKey, privateKey); | |
191 | 145 | return true; |
192 | 146 | } else { |
193 | 147 | return false; |
... | ... | @@ -198,105 +152,4 @@ public class LwM2MTransportBootstrapService { |
198 | 152 | } |
199 | 153 | } |
200 | 154 | |
201 | - private void infoParamsServerX509(X509Certificate certificate, PublicKey publicKey, PrivateKey privateKey) { | |
202 | - try { | |
203 | - this.infoPramsUri("X509"); | |
204 | - log.info("\n- X509 Certificate (Hex): [{}]", | |
205 | - Hex.encodeHexString(certificate.getEncoded())); | |
206 | - this.infoParamsBootstrapServerKey(publicKey, privateKey); | |
207 | - } catch (CertificateEncodingException e) { | |
208 | - log.error("", e); | |
209 | - } | |
210 | - } | |
211 | - | |
212 | - private void infoPramsUri(String mode) { | |
213 | - log.info("Bootstrap Server uses [{}]: serverNoSecureURI : [{}:{}], serverSecureURI : [{}:{}]", | |
214 | - mode, | |
215 | - this.bootstrapConfig.getHost(), | |
216 | - this.bootstrapConfig.getPort(), | |
217 | - this.bootstrapConfig.getSecureHost(), | |
218 | - this.bootstrapConfig.getSecurePort()); | |
219 | - } | |
220 | - | |
221 | - | |
222 | - private boolean setServerRPK(LeshanBootstrapServerBuilder builder) { | |
223 | - try { | |
224 | - this.generateKeyForBootstrapRPK(); | |
225 | - if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && | |
226 | - this.privateKey != null && this.privateKey.getEncoded().length > 0) { | |
227 | - builder.setPublicKey(this.publicKey); | |
228 | -// builder.setCertificateChain(new X509Certificate[] { serverCertificate }); | |
229 | - /// Trust all certificates. | |
230 | - builder.setTrustedCertificates(new X509Certificate[0]); | |
231 | - builder.setPrivateKey(this.privateKey); | |
232 | - return true; | |
233 | - } | |
234 | - } catch (NoSuchAlgorithmException | InvalidParameterSpecException | InvalidKeySpecException e) { | |
235 | - log.error("Fail create Bootstrap Server with RPK", e); | |
236 | - } | |
237 | - return false; | |
238 | - } | |
239 | - | |
240 | - | |
241 | - /** | |
242 | - * From yml: bootstrap | |
243 | - * public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}" | |
244 | - * public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}" | |
245 | - * private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}" | |
246 | - */ | |
247 | - private void generateKeyForBootstrapRPK() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException { | |
248 | - /** Get Elliptic Curve Parameter spec for secp256r1 */ | |
249 | - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); | |
250 | - algoParameters.init(new ECGenParameterSpec("secp256r1")); | |
251 | - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); | |
252 | - LwM2MTransportBootstrapConfig serverConfig = this.bootstrapConfig; | |
253 | - if (StringUtils.isNotEmpty(serverConfig.getPublicX()) && StringUtils.isNotEmpty(serverConfig.getPublicY())) { | |
254 | - /** Get point values */ | |
255 | - byte[] publicX = Hex.decodeHex(serverConfig.getPublicX().toCharArray()); | |
256 | - byte[] publicY = Hex.decodeHex(serverConfig.getPublicY().toCharArray()); | |
257 | - /** Create key specs */ | |
258 | - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), | |
259 | - parameterSpec); | |
260 | - /** Get public key */ | |
261 | - this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); | |
262 | - } | |
263 | - String privateEncodedKey = serverConfig.getPrivateEncoded(); | |
264 | - if (StringUtils.isNotEmpty(privateEncodedKey)) { | |
265 | - /** Get private key */ | |
266 | - byte[] privateS = Hex.decodeHex(privateEncodedKey.toCharArray()); | |
267 | - try { | |
268 | - this.privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(privateS)); | |
269 | - } catch (InvalidKeySpecException ignore2) { | |
270 | - log.error("Invalid Bootstrap Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", privateEncodedKey); | |
271 | - } | |
272 | - } | |
273 | - } | |
274 | - | |
275 | - private void infoParamsBootstrapServerKey(PublicKey publicKey, PrivateKey privateKey) { | |
276 | - /** Get x coordinate */ | |
277 | - byte[] x = ((ECPublicKey) publicKey).getW().getAffineX().toByteArray(); | |
278 | - if (x[0] == 0) | |
279 | - x = Arrays.copyOfRange(x, 1, x.length); | |
280 | - | |
281 | - /** Get Y coordinate */ | |
282 | - byte[] y = ((ECPublicKey) publicKey).getW().getAffineY().toByteArray(); | |
283 | - if (y[0] == 0) | |
284 | - y = Arrays.copyOfRange(y, 1, y.length); | |
285 | - | |
286 | - /** Get Curves params */ | |
287 | - String params = ((ECPublicKey) publicKey).getParams().toString(); | |
288 | - String privHex = Hex.encodeHexString(privateKey.getEncoded()); | |
289 | - log.info("\n- Public Key (Hex): [{}] \n" + | |
290 | - "- Private Key (Hex): [{}], \n" + | |
291 | - "public_x: \"${LWM2M_SERVER_PUBLIC_X_BS:{}}\" \n" + | |
292 | - "public_y: \"${LWM2M_SERVER_PUBLIC_Y_BS:{}}\" \n" + | |
293 | - "private_encoded: \"${LWM2M_SERVER_PRIVATE_ENCODED_BS:{}}\" \n" + | |
294 | - "- Elliptic Curve parameters : [{}]", | |
295 | - Hex.encodeHexString(publicKey.getEncoded()), | |
296 | - privHex, | |
297 | - Hex.encodeHexString(x), | |
298 | - Hex.encodeHexString(y), | |
299 | - privHex, | |
300 | - params); | |
301 | - } | |
302 | 155 | } | ... | ... |
... | ... | @@ -27,12 +27,8 @@ public interface LwM2MSecureServerConfig { |
27 | 27 | |
28 | 28 | Integer getSecurePort(); |
29 | 29 | |
30 | - String getPublicX(); | |
31 | - | |
32 | - String getPublicY(); | |
33 | - | |
34 | - String getPrivateEncoded(); | |
35 | - | |
36 | 30 | String getCertificateAlias(); |
37 | 31 | |
32 | + String getCertificatePassword(); | |
33 | + | |
38 | 34 | } | ... | ... |
... | ... | @@ -47,19 +47,11 @@ public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig { |
47 | 47 | private Integer securePort; |
48 | 48 | |
49 | 49 | @Getter |
50 | - @Value("${transport.lwm2m.bootstrap.security.public_x:}") | |
51 | - private String publicX; | |
52 | - | |
53 | - @Getter | |
54 | - @Value("${transport.lwm2m.bootstrap.security.public_y:}") | |
55 | - private String publicY; | |
56 | - | |
57 | - @Getter | |
58 | - @Value("${transport.lwm2m.bootstrap.security.private_encoded:}") | |
59 | - private String privateEncoded; | |
50 | + @Value("${transport.lwm2m.bootstrap.security.key_alias:}") | |
51 | + private String certificateAlias; | |
60 | 52 | |
61 | 53 | @Getter |
62 | - @Value("${transport.lwm2m.bootstrap.security.alias:}") | |
63 | - private String certificateAlias; | |
54 | + @Value("${transport.lwm2m.bootstrap.security.key_password:}") | |
55 | + private String certificatePassword; | |
64 | 56 | |
65 | 57 | } | ... | ... |
... | ... | @@ -53,11 +53,11 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { |
53 | 53 | private long sessionReportTimeout; |
54 | 54 | |
55 | 55 | @Getter |
56 | - @Value("${transport.lwm2m.recommended_ciphers:}") | |
56 | + @Value("${transport.lwm2m.security.recommended_ciphers:}") | |
57 | 57 | private boolean recommendedCiphers; |
58 | 58 | |
59 | 59 | @Getter |
60 | - @Value("${transport.lwm2m.recommended_supported_groups:}") | |
60 | + @Value("${transport.lwm2m.security.recommended_supported_groups:}") | |
61 | 61 | private boolean recommendedSupportedGroups; |
62 | 62 | |
63 | 63 | @Getter |
... | ... | @@ -97,10 +97,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { |
97 | 97 | private String rootCertificateAlias; |
98 | 98 | |
99 | 99 | @Getter |
100 | - @Value("${transport.lwm2m.security.enable_gen_new_key_psk_rpk:}") | |
101 | - private Boolean enableGenNewKeyPskRpk; | |
102 | - | |
103 | - @Getter | |
104 | 100 | @Value("${transport.lwm2m.server.id:}") |
105 | 101 | private Integer id; |
106 | 102 | |
... | ... | @@ -121,20 +117,12 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { |
121 | 117 | private Integer securePort; |
122 | 118 | |
123 | 119 | @Getter |
124 | - @Value("${transport.lwm2m.server.security.public_x:}") | |
125 | - private String publicX; | |
126 | - | |
127 | - @Getter | |
128 | - @Value("${transport.lwm2m.server.security.public_y:}") | |
129 | - private String publicY; | |
130 | - | |
131 | - @Getter | |
132 | - @Value("${transport.lwm2m.server.security.private_encoded:}") | |
133 | - private String privateEncoded; | |
120 | + @Value("${transport.lwm2m.server.security.key_alias:}") | |
121 | + private String certificateAlias; | |
134 | 122 | |
135 | 123 | @Getter |
136 | - @Value("${transport.lwm2m.server.security.alias:}") | |
137 | - private String certificateAlias; | |
124 | + @Value("${transport.lwm2m.server.security.key_password:}") | |
125 | + private String certificatePassword; | |
138 | 126 | |
139 | 127 | @Getter |
140 | 128 | @Value("${transport.lwm2m.log_max_length:}") | ... | ... |
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LWM2MGenerationPSkRPkECC.java
deleted
100644 → 0
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.transport.lwm2m.secure; | |
17 | - | |
18 | -import lombok.extern.slf4j.Slf4j; | |
19 | -import org.eclipse.leshan.core.util.Hex; | |
20 | - | |
21 | -import java.security.InvalidAlgorithmParameterException; | |
22 | -import java.security.KeyPair; | |
23 | -import java.security.KeyPairGenerator; | |
24 | -import java.security.NoSuchAlgorithmException; | |
25 | -import java.security.NoSuchProviderException; | |
26 | -import java.security.PrivateKey; | |
27 | -import java.security.PublicKey; | |
28 | -import java.security.SecureRandom; | |
29 | -import java.security.interfaces.ECPublicKey; | |
30 | -import java.security.spec.ECGenParameterSpec; | |
31 | -import java.util.Arrays; | |
32 | - | |
33 | -@Slf4j | |
34 | -public class LWM2MGenerationPSkRPkECC { | |
35 | - | |
36 | - public LWM2MGenerationPSkRPkECC() { | |
37 | - generationPSkKey(); | |
38 | - generationRPKECCKey(); | |
39 | - } | |
40 | - | |
41 | - private void generationPSkKey() { | |
42 | - /* PSK */ | |
43 | - int lenPSkKey = 32; | |
44 | - /* Start PSK | |
45 | - Clients and Servers MUST support PSK keys of up to 64 bytes in length, as required by [RFC7925] | |
46 | - SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong, as described in [RFC4086] | |
47 | - */ | |
48 | - SecureRandom randomPSK = new SecureRandom(); | |
49 | - byte[] bytesPSK = new byte[lenPSkKey]; | |
50 | - randomPSK.nextBytes(bytesPSK); | |
51 | - log.info("\nCreating new PSK: \n for the next start PSK -> security key: [{}]", Hex.encodeHexString(bytesPSK)); | |
52 | - } | |
53 | - | |
54 | - private void generationRPKECCKey() { | |
55 | - /* RPK */ | |
56 | - String algorithm = "EC"; | |
57 | - String provider = "SunEC"; | |
58 | - String nameParameterSpec = "secp256r1"; | |
59 | - | |
60 | - /* Start RPK | |
61 | - Elliptic Curve parameters : [secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)] | |
62 | - */ | |
63 | - KeyPairGenerator kpg = null; | |
64 | - try { | |
65 | - kpg = KeyPairGenerator.getInstance(algorithm, provider); | |
66 | - } catch (NoSuchAlgorithmException | NoSuchProviderException e) { | |
67 | - log.error("", e); | |
68 | - } | |
69 | - ECGenParameterSpec ecsp = new ECGenParameterSpec(nameParameterSpec); | |
70 | - try { | |
71 | - kpg.initialize(ecsp); | |
72 | - } catch (InvalidAlgorithmParameterException e) { | |
73 | - log.error("", e); | |
74 | - } | |
75 | - | |
76 | - KeyPair kp = kpg.genKeyPair(); | |
77 | - PrivateKey privKey = kp.getPrivate(); | |
78 | - PublicKey pubKey = kp.getPublic(); | |
79 | - | |
80 | - if (pubKey instanceof ECPublicKey) { | |
81 | - ECPublicKey ecPublicKey = (ECPublicKey) pubKey; | |
82 | - /* Get x coordinate */ | |
83 | - byte[] x = ecPublicKey.getW().getAffineX().toByteArray(); | |
84 | - if (x[0] == 0) | |
85 | - x = Arrays.copyOfRange(x, 1, x.length); | |
86 | - | |
87 | - /* Get Y coordinate */ | |
88 | - byte[] y = ecPublicKey.getW().getAffineY().toByteArray(); | |
89 | - if (y[0] == 0) | |
90 | - y = Arrays.copyOfRange(y, 1, y.length); | |
91 | - | |
92 | - /* Get Curves params */ | |
93 | - String privHex = Hex.encodeHexString(privKey.getEncoded()); | |
94 | - log.info("\nCreating new RPK for the next start... \n" + | |
95 | - " Public Key (Hex): [{}]\n" + | |
96 | - " Private Key (Hex): [{}]" + | |
97 | - " public_x : [{}] \n" + | |
98 | - " public_y : [{}] \n" + | |
99 | - " private_encode : [{}] \n" + | |
100 | - " Elliptic Curve parameters : [{}] \n", | |
101 | - Hex.encodeHexString(pubKey.getEncoded()), | |
102 | - privHex, | |
103 | - Hex.encodeHexString(x), | |
104 | - Hex.encodeHexString(y), | |
105 | - privHex, | |
106 | - ecPublicKey.getParams().toString()); | |
107 | - } | |
108 | - } | |
109 | -} | |
110 | - |
... | ... | @@ -22,17 +22,14 @@ import org.eclipse.californium.scandium.config.DtlsConnectorConfig; |
22 | 22 | import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; |
23 | 23 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; |
24 | 24 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; |
25 | -import org.eclipse.leshan.core.util.Hex; | |
26 | 25 | import org.eclipse.leshan.server.californium.LeshanServer; |
27 | 26 | import org.eclipse.leshan.server.californium.LeshanServerBuilder; |
28 | 27 | import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; |
29 | 28 | import org.eclipse.leshan.server.model.LwM2mModelProvider; |
30 | 29 | import org.springframework.stereotype.Component; |
31 | 30 | import org.thingsboard.server.cache.ota.OtaPackageDataCache; |
32 | -import org.thingsboard.server.common.data.StringUtils; | |
33 | 31 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
34 | 32 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; |
35 | -import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; | |
36 | 33 | import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; |
37 | 34 | import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier; |
38 | 35 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; |
... | ... | @@ -42,25 +39,9 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; |
42 | 39 | |
43 | 40 | import javax.annotation.PostConstruct; |
44 | 41 | import javax.annotation.PreDestroy; |
45 | -import java.math.BigInteger; | |
46 | -import java.security.AlgorithmParameters; | |
47 | -import java.security.KeyFactory; | |
48 | -import java.security.NoSuchAlgorithmException; | |
49 | 42 | import java.security.PrivateKey; |
50 | 43 | import java.security.PublicKey; |
51 | -import java.security.cert.Certificate; | |
52 | -import java.security.cert.CertificateEncodingException; | |
53 | 44 | import java.security.cert.X509Certificate; |
54 | -import java.security.interfaces.ECPublicKey; | |
55 | -import java.security.spec.ECGenParameterSpec; | |
56 | -import java.security.spec.ECParameterSpec; | |
57 | -import java.security.spec.ECPoint; | |
58 | -import java.security.spec.ECPublicKeySpec; | |
59 | -import java.security.spec.InvalidKeySpecException; | |
60 | -import java.security.spec.InvalidParameterSpecException; | |
61 | -import java.security.spec.KeySpec; | |
62 | -import java.security.spec.PKCS8EncodedKeySpec; | |
63 | -import java.util.Arrays; | |
64 | 45 | |
65 | 46 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; |
66 | 47 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; |
... | ... | @@ -77,8 +58,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
77 | 58 | |
78 | 59 | public static final CipherSuite[] RPK_OR_X509_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}; |
79 | 60 | public static final CipherSuite[] PSK_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256}; |
80 | - private PublicKey publicKey; | |
81 | - private PrivateKey privateKey; | |
82 | 61 | |
83 | 62 | private final LwM2mTransportContext context; |
84 | 63 | private final LwM2MTransportServerConfig config; |
... | ... | @@ -95,18 +74,14 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
95 | 74 | |
96 | 75 | @PostConstruct |
97 | 76 | public void init() { |
98 | - if (config.getEnableGenNewKeyPskRpk()) { | |
99 | - new LWM2MGenerationPSkRPkECC(); | |
100 | - } | |
101 | 77 | this.server = getLhServer(); |
102 | - /** | |
78 | + /* | |
103 | 79 | * Add a resource to the server. |
104 | 80 | * CoapResource -> |
105 | 81 | * path = FW_PACKAGE or SW_PACKAGE |
106 | 82 | * nameFile = "BC68JAR01A09_TO_BC68JAR01A10.bin" |
107 | 83 | * "coap://host:port/{path}/{token}/{nameFile}" |
108 | 84 | */ |
109 | - | |
110 | 85 | LwM2mTransportCoapResource otaCoapResource = new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE); |
111 | 86 | this.server.coap().getServer().add(otaCoapResource); |
112 | 87 | this.startLhServer(); |
... | ... | @@ -172,16 +147,11 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
172 | 147 | dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); |
173 | 148 | builder.setAuthorizer(authorizer); |
174 | 149 | dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); |
175 | - } else if (this.setServerRPK(builder)) { | |
176 | - this.infoPramsUri("RPK"); | |
177 | - this.infoParamsServerKey(this.publicKey, this.privateKey); | |
178 | - dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); | |
179 | 150 | } else { |
180 | 151 | /* by default trust all */ |
181 | 152 | builder.setTrustedCertificates(new X509Certificate[0]); |
182 | 153 | log.info("Unable to load X509 files for LWM2MServer"); |
183 | 154 | dtlsConfig.setSupportedCipherSuites(PSK_CIPHER_SUITES); |
184 | - this.infoPramsUri("PSK"); | |
185 | 155 | } |
186 | 156 | } |
187 | 157 | |
... | ... | @@ -189,13 +159,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
189 | 159 | try { |
190 | 160 | X509Certificate[] certificateChain = SslContextUtil.asX509Certificates(config.getKeyStoreValue().getCertificateChain(config.getCertificateAlias())); |
191 | 161 | X509Certificate serverCertificate = certificateChain[0]; |
192 | - PrivateKey privateKey = (PrivateKey) config.getKeyStoreValue().getKey(config.getCertificateAlias(), config.getKeyStorePassword() == null ? null : config.getKeyStorePassword().toCharArray()); | |
162 | + PrivateKey privateKey = (PrivateKey) config.getKeyStoreValue().getKey(config.getCertificateAlias(), config.getCertificatePassword() == null ? null : config.getCertificatePassword().toCharArray()); | |
193 | 163 | PublicKey publicKey = serverCertificate.getPublicKey(); |
194 | 164 | if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) { |
195 | 165 | builder.setPublicKey(serverCertificate.getPublicKey()); |
196 | 166 | builder.setPrivateKey(privateKey); |
197 | 167 | builder.setCertificateChain(certificateChain); |
198 | - this.infoParamsServerX509(serverCertificate, publicKey, privateKey); | |
199 | 168 | return true; |
200 | 169 | } else { |
201 | 170 | return false; |
... | ... | @@ -206,93 +175,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { |
206 | 175 | } |
207 | 176 | } |
208 | 177 | |
209 | - private void infoParamsServerX509(X509Certificate certificate, PublicKey publicKey, PrivateKey privateKey) { | |
210 | - try { | |
211 | - infoPramsUri("X509"); | |
212 | - log.info("\n- X509 Certificate (Hex): [{}]", | |
213 | - Hex.encodeHexString(certificate.getEncoded())); | |
214 | - this.infoParamsServerKey(publicKey, privateKey); | |
215 | - } catch (CertificateEncodingException e) { | |
216 | - log.error("", e); | |
217 | - } | |
218 | - } | |
219 | - | |
220 | - private void infoPramsUri(String mode) { | |
221 | - LwM2MTransportServerConfig lwM2MTransportServerConfig = config; | |
222 | - log.info("Server uses [{}]: serverNoSecureURI : [{}:{}], serverSecureURI : [{}:{}]", mode, | |
223 | - lwM2MTransportServerConfig.getHost(), | |
224 | - lwM2MTransportServerConfig.getPort(), | |
225 | - lwM2MTransportServerConfig.getSecureHost(), | |
226 | - lwM2MTransportServerConfig.getSecurePort()); | |
227 | - } | |
228 | - | |
229 | - private boolean setServerRPK(LeshanServerBuilder builder) { | |
230 | - try { | |
231 | - this.loadOrGenerateRPKKeys(); | |
232 | - if (this.publicKey != null && this.publicKey.getEncoded().length > 0 && | |
233 | - this.privateKey != null && this.privateKey.getEncoded().length > 0) { | |
234 | - builder.setPublicKey(this.publicKey); | |
235 | - builder.setPrivateKey(this.privateKey); | |
236 | - return true; | |
237 | - } | |
238 | - } catch (NoSuchAlgorithmException | InvalidParameterSpecException | InvalidKeySpecException e) { | |
239 | - log.error("Fail create Server with RPK", e); | |
240 | - } | |
241 | - return false; | |
242 | - } | |
243 | - | |
244 | - private void loadOrGenerateRPKKeys() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException { | |
245 | - /* Get Elliptic Curve Parameter spec for secp256r1 */ | |
246 | - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); | |
247 | - algoParameters.init(new ECGenParameterSpec("secp256r1")); | |
248 | - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); | |
249 | - LwM2MTransportServerConfig serverConfig = config; | |
250 | - if (StringUtils.isNotEmpty(serverConfig.getPublicX()) && StringUtils.isNotEmpty(serverConfig.getPublicY())) { | |
251 | - byte[] publicX = Hex.decodeHex(serverConfig.getPublicX().toCharArray()); | |
252 | - byte[] publicY = Hex.decodeHex(serverConfig.getPublicY().toCharArray()); | |
253 | - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), | |
254 | - parameterSpec); | |
255 | - this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); | |
256 | - } | |
257 | - String privateEncodedKey = serverConfig.getPrivateEncoded(); | |
258 | - if (StringUtils.isNotEmpty(privateEncodedKey)) { | |
259 | - byte[] privateS = Hex.decodeHex(privateEncodedKey.toCharArray()); | |
260 | - try { | |
261 | - this.privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(privateS)); | |
262 | - } catch (InvalidKeySpecException ignore2) { | |
263 | - log.error("Invalid Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", privateEncodedKey); | |
264 | - } | |
265 | - } | |
266 | - } | |
267 | - | |
268 | - private void infoParamsServerKey(PublicKey publicKey, PrivateKey privateKey) { | |
269 | - /* Get x coordinate */ | |
270 | - byte[] x = ((ECPublicKey) publicKey).getW().getAffineX().toByteArray(); | |
271 | - if (x[0] == 0) | |
272 | - x = Arrays.copyOfRange(x, 1, x.length); | |
273 | - | |
274 | - /* Get Y coordinate */ | |
275 | - byte[] y = ((ECPublicKey) publicKey).getW().getAffineY().toByteArray(); | |
276 | - if (y[0] == 0) | |
277 | - y = Arrays.copyOfRange(y, 1, y.length); | |
278 | - | |
279 | - /* Get Curves params */ | |
280 | - String params = ((ECPublicKey) publicKey).getParams().toString(); | |
281 | - String privHex = Hex.encodeHexString(privateKey.getEncoded()); | |
282 | - log.info(" \n- Public Key (Hex): [{}] \n" + | |
283 | - "- Private Key (Hex): [{}], \n" + | |
284 | - "public_x: \"${LWM2M_SERVER_PUBLIC_X:{}}\" \n" + | |
285 | - "public_y: \"${LWM2M_SERVER_PUBLIC_Y:{}}\" \n" + | |
286 | - "private_encoded: \"${LWM2M_SERVER_PRIVATE_ENCODED:{}}\" \n" + | |
287 | - "- Elliptic Curve parameters : [{}]", | |
288 | - Hex.encodeHexString(publicKey.getEncoded()), | |
289 | - privHex, | |
290 | - Hex.encodeHexString(x), | |
291 | - Hex.encodeHexString(y), | |
292 | - privHex, | |
293 | - params); | |
294 | - } | |
295 | - | |
296 | 178 | @Override |
297 | 179 | public String getName() { |
298 | 180 | return "LWM2M"; | ... | ... |
... | ... | @@ -19,10 +19,12 @@ import com.google.common.util.concurrent.Futures; |
19 | 19 | import com.google.common.util.concurrent.ListenableFuture; |
20 | 20 | import com.google.common.util.concurrent.MoreExecutors; |
21 | 21 | import lombok.extern.slf4j.Slf4j; |
22 | +import org.springframework.beans.factory.annotation.Value; | |
22 | 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
23 | 24 | import org.springframework.cache.Cache; |
24 | 25 | import org.springframework.context.annotation.Primary; |
25 | 26 | import org.springframework.stereotype.Service; |
27 | +import org.springframework.util.StringUtils; | |
26 | 28 | import org.thingsboard.server.common.data.EntityType; |
27 | 29 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
28 | 30 | import org.thingsboard.server.common.data.id.EntityId; |
... | ... | @@ -34,6 +36,7 @@ import org.thingsboard.server.common.stats.StatsFactory; |
34 | 36 | import org.thingsboard.server.dao.cache.CacheExecutorService; |
35 | 37 | import org.thingsboard.server.dao.service.Validator; |
36 | 38 | |
39 | +import javax.annotation.PostConstruct; | |
37 | 40 | import java.util.ArrayList; |
38 | 41 | import java.util.Collection; |
39 | 42 | import java.util.HashMap; |
... | ... | @@ -43,6 +46,7 @@ import java.util.Map; |
43 | 46 | import java.util.Objects; |
44 | 47 | import java.util.Optional; |
45 | 48 | import java.util.Set; |
49 | +import java.util.concurrent.Executor; | |
46 | 50 | import java.util.stream.Collectors; |
47 | 51 | |
48 | 52 | import static org.thingsboard.server.dao.attributes.AttributeUtils.validate; |
... | ... | @@ -53,12 +57,17 @@ import static org.thingsboard.server.dao.attributes.AttributeUtils.validate; |
53 | 57 | @Slf4j |
54 | 58 | public class CachedAttributesService implements AttributesService { |
55 | 59 | private static final String STATS_NAME = "attributes.cache"; |
60 | + public static final String LOCAL_CACHE_TYPE = "caffeine"; | |
56 | 61 | |
57 | 62 | private final AttributesDao attributesDao; |
58 | 63 | private final AttributesCacheWrapper cacheWrapper; |
64 | + private final CacheExecutorService cacheExecutorService; | |
59 | 65 | private final DefaultCounter hitCounter; |
60 | 66 | private final DefaultCounter missCounter; |
61 | - private final CacheExecutorService cacheExecutorService; | |
67 | + private Executor cacheExecutor; | |
68 | + | |
69 | + @Value("${cache.type}") | |
70 | + private String cacheType; | |
62 | 71 | |
63 | 72 | public CachedAttributesService(AttributesDao attributesDao, |
64 | 73 | AttributesCacheWrapper cacheWrapper, |
... | ... | @@ -72,6 +81,25 @@ public class CachedAttributesService implements AttributesService { |
72 | 81 | this.missCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "miss"); |
73 | 82 | } |
74 | 83 | |
84 | + @PostConstruct | |
85 | + public void init() { | |
86 | + this.cacheExecutor = getExecutor(cacheType, cacheExecutorService); | |
87 | + } | |
88 | + | |
89 | + /** | |
90 | + * Will return: | |
91 | + * - for the <b>local</b> cache type (cache.type="coffeine"): directExecutor (run callback immediately in the same thread) | |
92 | + * - for the <b>remote</b> cache: dedicated thread pool for the cache IO calls to unblock any caller thread | |
93 | + * */ | |
94 | + Executor getExecutor(String cacheType, CacheExecutorService cacheExecutorService) { | |
95 | + if (StringUtils.isEmpty(cacheType) || LOCAL_CACHE_TYPE.equals(cacheType)) { | |
96 | + log.info("Going to use directExecutor for the local cache type {}", cacheType); | |
97 | + return MoreExecutors.directExecutor(); | |
98 | + } | |
99 | + log.info("Going to use cacheExecutorService for the remote cache type {}", cacheType); | |
100 | + return cacheExecutorService; | |
101 | + } | |
102 | + | |
75 | 103 | @Override |
76 | 104 | public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, String attributeKey) { |
77 | 105 | validate(entityId, scope); |
... | ... | @@ -90,7 +118,7 @@ public class CachedAttributesService implements AttributesService { |
90 | 118 | // TODO: think if it's a good idea to store 'empty' attributes |
91 | 119 | cacheWrapper.put(attributeCacheKey, foundAttrKvEntry.orElse(null)); |
92 | 120 | return foundAttrKvEntry; |
93 | - }, cacheExecutorService); | |
121 | + }, cacheExecutor); | |
94 | 122 | } |
95 | 123 | } |
96 | 124 | |
... | ... | @@ -113,7 +141,7 @@ public class CachedAttributesService implements AttributesService { |
113 | 141 | notFoundAttributeKeys.removeAll(wrappedCachedAttributes.keySet()); |
114 | 142 | |
115 | 143 | ListenableFuture<List<AttributeKvEntry>> result = attributesDao.find(tenantId, entityId, scope, notFoundAttributeKeys); |
116 | - return Futures.transform(result, foundInDbAttributes -> mergeDbAndCacheAttributes(entityId, scope, cachedAttributes, notFoundAttributeKeys, foundInDbAttributes), cacheExecutorService); | |
144 | + return Futures.transform(result, foundInDbAttributes -> mergeDbAndCacheAttributes(entityId, scope, cachedAttributes, notFoundAttributeKeys, foundInDbAttributes), cacheExecutor); | |
117 | 145 | |
118 | 146 | } |
119 | 147 | |
... | ... | @@ -171,7 +199,7 @@ public class CachedAttributesService implements AttributesService { |
171 | 199 | |
172 | 200 | // TODO: can do if (attributesCache.get() != null) attributesCache.put() instead, but will be more twice more requests to cache |
173 | 201 | List<String> attributeKeys = attributes.stream().map(KvEntry::getKey).collect(Collectors.toList()); |
174 | - future.addListener(() -> evictAttributesFromCache(tenantId, entityId, scope, attributeKeys), cacheExecutorService); | |
202 | + future.addListener(() -> evictAttributesFromCache(tenantId, entityId, scope, attributeKeys), cacheExecutor); | |
175 | 203 | return future; |
176 | 204 | } |
177 | 205 | |
... | ... | @@ -179,7 +207,7 @@ public class CachedAttributesService implements AttributesService { |
179 | 207 | public ListenableFuture<List<Void>> removeAll(TenantId tenantId, EntityId entityId, String scope, List<String> attributeKeys) { |
180 | 208 | validate(entityId, scope); |
181 | 209 | ListenableFuture<List<Void>> future = attributesDao.removeAll(tenantId, entityId, scope, attributeKeys); |
182 | - future.addListener(() -> evictAttributesFromCache(tenantId, entityId, scope, attributeKeys), cacheExecutorService); | |
210 | + future.addListener(() -> evictAttributesFromCache(tenantId, entityId, scope, attributeKeys), cacheExecutor); | |
183 | 211 | return future; |
184 | 212 | } |
185 | 213 | ... | ... |
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.dao.attributes; | |
17 | + | |
18 | +import com.google.common.util.concurrent.MoreExecutors; | |
19 | +import org.junit.Test; | |
20 | +import org.thingsboard.server.dao.cache.CacheExecutorService; | |
21 | + | |
22 | +import static org.hamcrest.CoreMatchers.is; | |
23 | +import static org.hamcrest.MatcherAssert.assertThat; | |
24 | +import static org.mockito.ArgumentMatchers.any; | |
25 | +import static org.mockito.BDDMockito.willCallRealMethod; | |
26 | +import static org.mockito.Mockito.mock; | |
27 | + | |
28 | +public class CachedAttributesServiceTest { | |
29 | + | |
30 | + public static final String REDIS = "redis"; | |
31 | + | |
32 | + @Test | |
33 | + public void givenLocalCacheTypeName_whenEquals_thenOK() { | |
34 | + assertThat(CachedAttributesService.LOCAL_CACHE_TYPE, is("caffeine")); | |
35 | + } | |
36 | + | |
37 | + @Test | |
38 | + public void givenCacheType_whenGetExecutor_thenDirectExecutor() { | |
39 | + CachedAttributesService cachedAttributesService = mock(CachedAttributesService.class); | |
40 | + CacheExecutorService cacheExecutorService = mock(CacheExecutorService.class); | |
41 | + willCallRealMethod().given(cachedAttributesService).getExecutor(any(), any()); | |
42 | + | |
43 | + assertThat(cachedAttributesService.getExecutor(null, cacheExecutorService), is(MoreExecutors.directExecutor())); | |
44 | + | |
45 | + assertThat(cachedAttributesService.getExecutor("", cacheExecutorService), is(MoreExecutors.directExecutor())); | |
46 | + | |
47 | + assertThat(cachedAttributesService.getExecutor(CachedAttributesService.LOCAL_CACHE_TYPE, cacheExecutorService), is(MoreExecutors.directExecutor())); | |
48 | + | |
49 | + } | |
50 | + | |
51 | + @Test | |
52 | + public void givenCacheType_whenGetExecutor_thenReturnCacheExecutorService() { | |
53 | + CachedAttributesService cachedAttributesService = mock(CachedAttributesService.class); | |
54 | + CacheExecutorService cacheExecutorService = mock(CacheExecutorService.class); | |
55 | + willCallRealMethod().given(cachedAttributesService).getExecutor(any(String.class), any(CacheExecutorService.class)); | |
56 | + | |
57 | + assertThat(cachedAttributesService.getExecutor(REDIS, cacheExecutorService), is(cacheExecutorService)); | |
58 | + | |
59 | + assertThat(cachedAttributesService.getExecutor("unknownCacheType", cacheExecutorService), is(cacheExecutorService)); | |
60 | + | |
61 | + } | |
62 | + | |
63 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -106,47 +106,40 @@ transport: |
106 | 106 | bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" |
107 | 107 | bind_port: "${LWM2M_BIND_PORT:5685}" |
108 | 108 | security: |
109 | - bind_address: "${LWM2M_BIND_ADDRESS_SECURITY:0.0.0.0}" | |
110 | - bind_port: "${LWM2M_BIND_PORT_SECURITY:5686}" | |
111 | - # Only for RPK: Public & Private Key. If the keystore file is missing or not working | |
112 | - public_x: "${LWM2M_SERVER_PUBLIC_X:05064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f358}" | |
113 | - public_y: "${LWM2M_SERVER_PUBLIC_Y:5eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}" | |
114 | - private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}" | |
109 | + bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" | |
110 | + bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}" | |
115 | 111 | # Only Certificate_x509: |
116 | - alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}" | |
112 | + key_alias: "${LWM2M_SERVER_KEY_ALIAS:server}" | |
113 | + key_password: "${LWM2M_SERVER_KEY_PASSWORD:server_ks_password}" | |
117 | 114 | skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" |
118 | 115 | bootstrap: |
119 | 116 | enable: "${LWM2M_ENABLED_BS:true}" |
120 | 117 | id: "${LWM2M_SERVER_ID_BS:111}" |
121 | - bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" | |
122 | - bind_port: "${LWM2M_BIND_PORT_BS:5687}" | |
118 | + bind_address: "${LWM2M_BS_BIND_ADDRESS:0.0.0.0}" | |
119 | + bind_port: "${LWM2M_BS_BIND_PORT:5687}" | |
123 | 120 | security: |
124 | - bind_address: "${LWM2M_BIND_ADDRESS_SECURITY_BS:0.0.0.0}" | |
125 | - bind_port: "${LWM2M_BIND_PORT_SECURITY_BS:5688}" | |
126 | - # Only for RPK: Public & Private Key. If the keystore file is missing or not working | |
127 | - public_x: "${LWM2M_SERVER_PUBLIC_X_BS:5017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f91}" | |
128 | - public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:3fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" | |
129 | - private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" | |
121 | + bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" | |
122 | + bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}" | |
130 | 123 | # Only Certificate_x509: |
131 | - alias: "${LWM2M_KEYSTORE_ALIAS_BS:bootstrap}" | |
124 | + key_alias: "${LWM2M_BS_KEY_ALIAS:bootstrap}" | |
125 | + key_password: "${LWM2M_BS_KEY_PASSWORD:server_ks_password}" | |
132 | 126 | security: |
133 | 127 | # Certificate_x509: |
134 | 128 | # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format |
135 | 129 | # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh |
136 | 130 | key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}" |
137 | 131 | # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks" |
138 | - key_store: "${LWM2M_KEY_STORE:lwm2mserver.jks}" | |
139 | - key_store_password: "${LWM2M_KEY_STORE_PASSWORD:server_ks_password}" | |
140 | - root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}" | |
141 | - enable_gen_new_key_psk_rpk: "${ENABLE_GEN_NEW_KEY_PSK_RPK:false}" | |
132 | + key_store: "${LWM2M_KEYSTORE:lwm2mserver.jks}" | |
133 | + key_store_password: "${LWM2M_KEYSTORE_PASSWORD:server_ks_password}" | |
134 | + root_alias: "${LWM2M_SERVER_ROOT_CA_ALIAS:rootca}" | |
135 | + recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" | |
136 | + recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" | |
142 | 137 | timeout: "${LWM2M_TIMEOUT:120000}" |
143 | - recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" | |
144 | - recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" | |
145 | 138 | uplink_pool_size: "${LWM2M_UPLINK_POOL_SIZE:10}" |
146 | 139 | downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}" |
147 | 140 | ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" |
148 | 141 | clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" |
149 | - log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}" | |
142 | + log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" | |
150 | 143 | # Use redis for Security and Registration stores |
151 | 144 | redis.enabled: "${LWM2M_REDIS_ENABLED:false}" |
152 | 145 | ... | ... |