Commit b864680b812e86ecc6d1ba032256768fa05ab3fa

Authored by nickAS21
Committed by Andrew Shvayka
1 parent 4c12985a

Lwm2m: back: start DTLS -one server 4 security

@@ -217,23 +217,19 @@ public class LwM2MModelsRepository { @@ -217,23 +217,19 @@ public class LwM2MModelsRepository {
217 switch (mode) { 217 switch (mode) {
218 case NO_SEC: 218 case NO_SEC:
219 bsServ.setHost(contextBootStrap.getBootstrapHost()); 219 bsServ.setHost(contextBootStrap.getBootstrapHost());
220 - bsServ.setPort(contextBootStrap.getBootstrapPortNoSecPsk()); 220 + bsServ.setPort(contextBootStrap.getBootstrapPortNoSec());
221 bsServ.setServerPublicKey(""); 221 bsServ.setServerPublicKey("");
222 break; 222 break;
223 case PSK: 223 case PSK:
224 - bsServ.setHost(contextBootStrap.getBootstrapSecureHost());  
225 - bsServ.setPort(contextBootStrap.getBootstrapSecurePortPsk()); 224 + bsServ.setHost(contextBootStrap.getBootstrapHostSecurity());
  225 + bsServ.setPort(contextBootStrap.getBootstrapPortSecurity());
226 bsServ.setServerPublicKey(""); 226 bsServ.setServerPublicKey("");
227 break; 227 break;
228 case RPK: 228 case RPK:
229 - bsServ.setHost(contextBootStrap.getBootstrapSecureHost());  
230 - bsServ.setPort(contextBootStrap.getBootstrapSecurePortRpk());  
231 - bsServ.setServerPublicKey(getRPKPublicKey(this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY()));  
232 - break;  
233 case X509: 229 case X509:
234 - bsServ.setHost(contextBootStrap.getBootstrapSecureHost());  
235 - bsServ.setPort(contextBootStrap.getBootstrapSecurePortX509());  
236 - bsServ.setServerPublicKey(getServerPublicKeyX509(contextBootStrap.getBootstrapAlias())); 230 + bsServ.setHost(contextBootStrap.getBootstrapHostSecurity());
  231 + bsServ.setPort(contextBootStrap.getBootstrapPortSecurity());
  232 + bsServ.setServerPublicKey(getPublicKey (contextBootStrap.getBootstrapAlias(), this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY()));
237 break; 233 break;
238 default: 234 default:
239 break; 235 break;
@@ -243,23 +239,19 @@ public class LwM2MModelsRepository { @@ -243,23 +239,19 @@ public class LwM2MModelsRepository {
243 switch (mode) { 239 switch (mode) {
244 case NO_SEC: 240 case NO_SEC:
245 bsServ.setHost(contextServer.getServerHost()); 241 bsServ.setHost(contextServer.getServerHost());
246 - bsServ.setPort(contextServer.getServerPortNoSecPsk()); 242 + bsServ.setPort(contextServer.getServerPortNoSec());
247 bsServ.setServerPublicKey(""); 243 bsServ.setServerPublicKey("");
248 break; 244 break;
249 case PSK: 245 case PSK:
250 - bsServ.setHost(contextServer.getServerSecureHost());  
251 - bsServ.setPort(contextServer.getServerPortPsk()); 246 + bsServ.setHost(contextServer.getServerHostSecurity());
  247 + bsServ.setPort(contextServer.getServerPortSecurity());
252 bsServ.setServerPublicKey(""); 248 bsServ.setServerPublicKey("");
253 break; 249 break;
254 case RPK: 250 case RPK:
255 - bsServ.setHost(contextServer.getServerSecureHost());  
256 - bsServ.setPort(contextServer.getServerPortRpk());  
257 - bsServ.setServerPublicKey(getRPKPublicKey(this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY()));  
258 - break;  
259 case X509: 251 case X509:
260 - bsServ.setHost(contextServer.getServerSecureHost());  
261 - bsServ.setPort(contextServer.getServerPortX509());  
262 - bsServ.setServerPublicKey(getServerPublicKeyX509(contextServer.getServerAlias())); 252 + bsServ.setHost(contextServer.getServerHostSecurity());
  253 + bsServ.setPort(contextServer.getServerPortSecurity());
  254 + bsServ.setServerPublicKey(getPublicKey (contextServer.getServerAlias(), this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY()));
263 break; 255 break;
264 default: 256 default:
265 break; 257 break;
@@ -268,6 +260,11 @@ public class LwM2MModelsRepository { @@ -268,6 +260,11 @@ public class LwM2MModelsRepository {
268 return bsServ; 260 return bsServ;
269 } 261 }
270 262
  263 + private String getPublicKey (String alias, String publicServerX, String publicServerY) {
  264 + String publicKey = getServerPublicKeyX509(alias);
  265 + return publicKey != null ? publicKey : getRPKPublicKey(publicServerX, publicServerY);
  266 + }
  267 +
271 /** 268 /**
272 * @param alias 269 * @param alias
273 * @return PublicKey format HexString or null 270 * @return PublicKey format HexString or null
@@ -584,7 +584,7 @@ transport: @@ -584,7 +584,7 @@ transport:
584 update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}" 584 update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}"
585 un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}" 585 un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}"
586 secure: 586 secure:
587 - # Only Certificate_x509: 587 + # Certificate_x509:
588 # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format 588 # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
589 # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh 589 # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
590 key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}" 590 key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
@@ -597,18 +597,11 @@ transport: @@ -597,18 +597,11 @@ transport:
597 server: 597 server:
598 id: "${LWM2M_SERVER_ID:123}" 598 id: "${LWM2M_SERVER_ID:123}"
599 bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" 599 bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}"
600 - bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_PSK:5685}"  
601 - bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_RPK:5687}"  
602 - bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_X509:5689}" 600 + bind_port_no_sec: "${LWM2M_BIND_PORT_NO_SEC:5685}"
603 secure: 601 secure:
604 - bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}"  
605 - start_psk: "${START_SERVER_PSK:true}"  
606 - start_rpk: "${START_SERVER_RPK:true}"  
607 - start_x509: "${START_SERVER_X509:true}"  
608 - bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK:5686}"  
609 - bind_port_rpk: "${LWM2M_BIND_PORT_SEC_RPK:5688}"  
610 - bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509:5690}"  
611 - # Only RPK: Public & Private Key 602 + bind_address_security: "${LWM2M_BIND_ADDRESS_SECURITY:0.0.0.0}"
  603 + bind_port_security: "${LWM2M_BIND_PORT_SECURITY:5686}"
  604 + # Only for RPK: Public & Private Key. If the keystore file is missing or not working
612 # create_rpk: "${CREATE_RPK:}" 605 # create_rpk: "${CREATE_RPK:}"
613 public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}" 606 public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}"
614 public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}" 607 public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}"
@@ -619,18 +612,11 @@ transport: @@ -619,18 +612,11 @@ transport:
619 enable: "${LWM2M_BOOTSTRAP_ENABLED:true}" 612 enable: "${LWM2M_BOOTSTRAP_ENABLED:true}"
620 id: "${LWM2M_SERVER_ID:111}" 613 id: "${LWM2M_SERVER_ID:111}"
621 bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" 614 bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
622 - bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_BS:5691}"  
623 - bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_BS:5693}"  
624 - bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_BS:5695}" 615 + bind_port_no_sec: "${LWM2M_BIND_PORT_NO_SEC_BS:5687}"
625 secure: 616 secure:
626 - bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"  
627 - start_psk: "${START_SERVER_PSK_BS:true}"  
628 - start_rpk: "${START_SERVER_RPK_BS:true}"  
629 - start_x509: "${START_SERVER_X509_BS:true}"  
630 - bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK_BS:5692}"  
631 - bind_port_rpk: "${LWM2M_BIND_PORT_SER_RPK_BS:5694}"  
632 - bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509_BS:5696}"  
633 - # Only RPK: Public & Private Key 617 + bind_address_security: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
  618 + bind_port_security: "${LWM2M_BIND_PORT_SEC_BS:5688}"
  619 + # Only for RPK: Public & Private Key. If the keystore file is missing or not working
634 public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}" 620 public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}"
635 public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}" 621 public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}"
636 private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}" 622 private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}"
@@ -25,20 +25,18 @@ import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuil @@ -25,20 +25,18 @@ import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuil
25 import org.springframework.beans.factory.annotation.Autowired; 25 import org.springframework.beans.factory.annotation.Autowired;
26 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 26 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
27 import org.springframework.context.annotation.Bean; 27 import org.springframework.context.annotation.Bean;
28 -import org.springframework.context.annotation.Primary;  
29 import org.springframework.stereotype.Component; 28 import org.springframework.stereotype.Component;
30 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; 29 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore;
31 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; 30 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore;
32 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; 31 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager;
33 -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;  
34 import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; 32 import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer;
35 33
36 import java.math.BigInteger; 34 import java.math.BigInteger;
37 import java.security.AlgorithmParameters; 35 import java.security.AlgorithmParameters;
38 -import java.security.GeneralSecurityException;  
39 import java.security.KeyFactory; 36 import java.security.KeyFactory;
40 import java.security.KeyStore; 37 import java.security.KeyStore;
41 import java.security.KeyStoreException; 38 import java.security.KeyStoreException;
  39 +import java.security.NoSuchAlgorithmException;
42 import java.security.PrivateKey; 40 import java.security.PrivateKey;
43 import java.security.PublicKey; 41 import java.security.PublicKey;
44 import java.security.cert.CertificateEncodingException; 42 import java.security.cert.CertificateEncodingException;
@@ -49,14 +47,13 @@ import java.security.spec.ECParameterSpec; @@ -49,14 +47,13 @@ import java.security.spec.ECParameterSpec;
49 import java.security.spec.ECPoint; 47 import java.security.spec.ECPoint;
50 import java.security.spec.ECPrivateKeySpec; 48 import java.security.spec.ECPrivateKeySpec;
51 import java.security.spec.ECPublicKeySpec; 49 import java.security.spec.ECPublicKeySpec;
  50 +import java.security.spec.InvalidKeySpecException;
  51 +import java.security.spec.InvalidParameterSpecException;
52 import java.security.spec.KeySpec; 52 import java.security.spec.KeySpec;
53 import java.util.Arrays; 53 import java.util.Arrays;
54 54
  55 +import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
55 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; 56 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256;
56 -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC;  
57 -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.PSK;  
58 -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK;  
59 -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509;  
60 import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; 57 import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig;
61 58
62 @Slf4j 59 @Slf4j
@@ -78,61 +75,42 @@ public class LwM2MTransportBootstrapServerConfiguration { @@ -78,61 +75,42 @@ public class LwM2MTransportBootstrapServerConfiguration {
78 @Autowired 75 @Autowired
79 private LwM2MInMemoryBootstrapConfigStore lwM2MInMemoryBootstrapConfigStore; 76 private LwM2MInMemoryBootstrapConfigStore lwM2MInMemoryBootstrapConfigStore;
80 77
81 - @Primary  
82 - @Bean(name = "leshanBootstrapX509")  
83 - @ConditionalOnExpression("('${transport.lwm2m.bootstrap.secure.start_x509:false}'=='true')")  
84 - public LeshanBootstrapServer getLeshanBootstrapServerX509() {  
85 - log.info("Prepare and start BootstrapServerX509... PostConstruct");  
86 - return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSecX509(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortX509(), X509);  
87 - }  
88 -  
89 - @Bean(name = "leshanBootstrapPsk")  
90 - @ConditionalOnExpression("('${transport.lwm2m.bootstrap.secure.start_psk:false}'=='true')")  
91 - public LeshanBootstrapServer getLeshanBootstrapServerPsk() {  
92 - log.info("Prepare and start BootstrapServerRsk... PostConstruct");  
93 - return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSecPsk(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortPsk(), PSK);  
94 - }  
95 78
96 - @Bean(name = "leshanBootstrapRpk")  
97 - @ConditionalOnExpression("('${transport.lwm2m.bootstrap.secure.start_rpk:false}'=='true')")  
98 - public LeshanBootstrapServer getLeshanBootstrapServerRpk() {  
99 - log.info("Prepare and start BootstrapServerRpk... PostConstruct");  
100 - return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSecRpk(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortRpk(), RPK); 79 + @Bean
  80 + public LeshanBootstrapServer getLeshanBootstrapServer() {
  81 + log.info("Prepare and start BootstrapServer... PostConstruct");
  82 + return this.getLhBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSec(), this.contextBs.getCtxBootStrap().getBootstrapPortSecurity());
101 } 83 }
102 84
103 - public LeshanBootstrapServer getLeshanBootstrapServer(Integer bootstrapPortNoSec, Integer bootstrapSecurePort, LwM2MSecurityMode dtlsMode) { 85 + public LeshanBootstrapServer getLhBootstrapServer(Integer bootstrapPortNoSec, Integer bootstrapSecurePort) {
104 LeshanBootstrapServerBuilder builder = new LeshanBootstrapServerBuilder(); 86 LeshanBootstrapServerBuilder builder = new LeshanBootstrapServerBuilder();
105 builder.setLocalAddress(this.contextBs.getCtxBootStrap().getBootstrapHost(), bootstrapPortNoSec); 87 builder.setLocalAddress(this.contextBs.getCtxBootStrap().getBootstrapHost(), bootstrapPortNoSec);
106 - builder.setLocalSecureAddress(this.contextBs.getCtxBootStrap().getBootstrapSecureHost(), bootstrapSecurePort); 88 + builder.setLocalSecureAddress(this.contextBs.getCtxBootStrap().getBootstrapHostSecurity(), bootstrapSecurePort);
107 89
108 /** Create CoAP Config */ 90 /** Create CoAP Config */
109 - builder.setCoapConfig(getCoapConfig (bootstrapPortNoSec, bootstrapSecurePort)); 91 + builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort));
  92 +
  93 + /** Define model provider (Create Models )*/
  94 + builder.setModel(new StaticModel(contextS.getCtxServer().getModelsValue()));
  95 +
  96 + /** Create credentials */
  97 + this.setServerWithCredentials(builder);
110 98
111 - /** ConfigStore */ 99 + /** Set securityStore with new ConfigStore */
112 builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore); 100 builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore);
113 101
114 /** SecurityStore */ 102 /** SecurityStore */
115 builder.setSecurityStore(lwM2MBootstrapSecurityStore); 103 builder.setSecurityStore(lwM2MBootstrapSecurityStore);
116 104
117 - /** Define model provider (Create Models )*/  
118 - builder.setModel(new StaticModel(contextS.getCtxServer().getModelsValue()));  
119 -  
120 - /** Create credentials */  
121 - LwM2MSetSecurityStoreBootstrap(builder, dtlsMode);  
122 105
123 /** Create and Set DTLS Config */ 106 /** Create and Set DTLS Config */
124 DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); 107 DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
125 - if (dtlsMode==PSK) {  
126 - dtlsConfig.setRecommendedCipherSuitesOnly(this.contextS.getCtxServer().isRecommendedCiphers());  
127 - dtlsConfig.setRecommendedSupportedGroupsOnly(this.contextS.getCtxServer().isRecommendedSupportedGroups());  
128 - dtlsConfig.setSupportedCipherSuites(TLS_PSK_WITH_AES_128_CBC_SHA256);  
129 - }  
130 - else {  
131 - dtlsConfig.setRecommendedCipherSuitesOnly(this.contextS.getCtxServer().isRecommendedCiphers());  
132 -// dtlsConfig.setRecommendedSupportedGroupsOnly(false);  
133 - }  
134 - builder.setDtlsConfig(dtlsConfig); 108 + dtlsConfig.setRecommendedSupportedGroupsOnly(!this.contextS.getCtxServer().isRecommendedSupportedGroups());
  109 + dtlsConfig.setRecommendedCipherSuitesOnly(this.contextS.getCtxServer().isRecommendedCiphers());
  110 + dtlsConfig.setSupportedCipherSuites(TLS_PSK_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256);
135 111
  112 + /** Set DTLS Config */
  113 + builder.setDtlsConfig(dtlsConfig);
136 114
137 BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore); 115 BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore);
138 builder.setSessionManager(sessionManager); 116 builder.setSessionManager(sessionManager);
@@ -141,150 +119,153 @@ public class LwM2MTransportBootstrapServerConfiguration { @@ -141,150 +119,153 @@ public class LwM2MTransportBootstrapServerConfiguration {
141 return builder.build(); 119 return builder.build();
142 } 120 }
143 121
144 - public void LwM2MSetSecurityStoreBootstrap(LeshanBootstrapServerBuilder builder, LwM2MSecurityMode dtlsMode) {  
145 -  
146 - /** Set securityStore with new registrationStore */  
147 -  
148 - switch (dtlsMode) {  
149 - /** Use No_Sec only */  
150 - case NO_SEC:  
151 - setServerWithX509Cert(builder, NO_SEC.code);  
152 - break;  
153 - /** Use PSK/RPK */  
154 - case PSK:  
155 - break;  
156 - case RPK:  
157 - setRPK(builder);  
158 - break;  
159 - case X509:  
160 - setServerWithX509Cert(builder, X509.code);  
161 - break;  
162 - /** Use X509_EST only */  
163 - case X509_EST:  
164 - // TODO support sentinel pool and make pool configurable  
165 - break;  
166 - /** Use ather X509, PSK, No_Sec ?? */  
167 - default:  
168 - break;  
169 - }  
170 - }  
171 -  
172 - private void setRPK(LeshanBootstrapServerBuilder builder) {  
173 - try {  
174 - /** Get Elliptic Curve Parameter spec for secp256r1 */  
175 - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");  
176 - algoParameters.init(new ECGenParameterSpec("secp256r1"));  
177 - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);  
178 - if (this.contextBs.getCtxBootStrap().getBootstrapPublicX() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicX().isEmpty() && this.contextBs.getCtxBootStrap().getBootstrapPublicY() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicY().isEmpty()) {  
179 - /** Get point values */  
180 - byte[] publicX = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicX().toCharArray());  
181 - byte[] publicY = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicY().toCharArray());  
182 - /** Create key specs */  
183 - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),  
184 - parameterSpec);  
185 - /** Get keys */  
186 - this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);  
187 - }  
188 - if (this.contextBs.getCtxBootStrap().getBootstrapPrivateS() != null && !this.contextBs.getCtxBootStrap().getBootstrapPrivateS().isEmpty()) {  
189 - /** Get point values */  
190 - byte[] privateS = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPrivateS().toCharArray());  
191 - /** Create key specs */  
192 - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec);  
193 - /** Get keys */  
194 - this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec);  
195 - }  
196 - if (this.publicKey != null && this.publicKey.getEncoded().length > 0 &&  
197 - this.privateKey != null && this.privateKey.getEncoded().length > 0) {  
198 - builder.setPublicKey(this.publicKey);  
199 - builder.setPrivateKey(this.privateKey);  
200 - this.contextBs.getCtxBootStrap().setBootstrapPublicKey(this.publicKey);  
201 - getParamsRPK();  
202 - }  
203 - } catch (GeneralSecurityException | IllegalArgumentException e) {  
204 - log.error("[{}] Failed generate Server PSK/RPK", e.getMessage());  
205 - throw new RuntimeException(e);  
206 - }  
207 - }  
208 -  
209 - private void setServerWithX509Cert(LeshanBootstrapServerBuilder builder, int securityModeCode) { 122 + private void setServerWithCredentials(LeshanBootstrapServerBuilder builder) {
210 try { 123 try {
211 if (this.contextS.getCtxServer().getKeyStoreValue() != null) { 124 if (this.contextS.getCtxServer().getKeyStoreValue() != null) {
212 KeyStore keyStoreServer = this.contextS.getCtxServer().getKeyStoreValue(); 125 KeyStore keyStoreServer = this.contextS.getCtxServer().getKeyStoreValue();
213 - setBuilderX509(builder);  
214 - X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(this.contextS.getCtxServer().getRootAlias());  
215 - if (rootCAX509Cert != null && securityModeCode == X509.code) {  
216 - X509Certificate[] trustedCertificates = new X509Certificate[1];  
217 - trustedCertificates[0] = rootCAX509Cert;  
218 - builder.setTrustedCertificates(trustedCertificates); 126 + if (this.setBuilderX509(builder)) {
  127 + X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(this.contextS.getCtxServer().getRootAlias());
  128 + if (rootCAX509Cert != null) {
  129 + X509Certificate[] trustedCertificates = new X509Certificate[1];
  130 + trustedCertificates[0] = rootCAX509Cert;
  131 + builder.setTrustedCertificates(trustedCertificates);
  132 + } else {
  133 + /** by default trust all */
  134 + builder.setTrustedCertificates(new X509Certificate[0]);
  135 + }
  136 + } else if (this.setServerRPK(builder)) {
  137 + this.infoParamsServerRPK();
219 } else { 138 } else {
220 /** by default trust all */ 139 /** by default trust all */
221 builder.setTrustedCertificates(new X509Certificate[0]); 140 builder.setTrustedCertificates(new X509Certificate[0]);
  141 + log.info("Unable to load X509 files for BootStrapServer");
  142 + this.infoParamsServerPSK();
222 } 143 }
223 } 144 }
224 - else {  
225 - /** by default trust all */  
226 - builder.setTrustedCertificates(new X509Certificate[0]);  
227 - log.error("Unable to load X509 files for BootStrapServer");  
228 - }  
229 } catch (KeyStoreException ex) { 145 } catch (KeyStoreException ex) {
230 log.error("[{}] Unable to load X509 files server", ex.getMessage()); 146 log.error("[{}] Unable to load X509 files server", ex.getMessage());
231 } 147 }
232 -  
233 } 148 }
234 149
235 - private void setBuilderX509(LeshanBootstrapServerBuilder builder) { 150 + private boolean setBuilderX509(LeshanBootstrapServerBuilder builder) {
236 /** 151 /**
237 * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE 152 * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE
238 * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks 153 * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks
239 */ 154 */
240 try { 155 try {
241 X509Certificate serverCertificate = (X509Certificate) this.contextS.getCtxServer().getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getBootstrapAlias()); 156 X509Certificate serverCertificate = (X509Certificate) this.contextS.getCtxServer().getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getBootstrapAlias());
242 - this.privateKey = (PrivateKey) this.contextS.getCtxServer().getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getBootstrapAlias(), this.contextS.getCtxServer().getKeyStorePasswordServer() == null ? null : this.contextS.getCtxServer().getKeyStorePasswordServer().toCharArray());  
243 - if (this.privateKey != null && this.privateKey.getEncoded().length > 0) {  
244 - builder.setPrivateKey(this.privateKey);  
245 - }  
246 - if (serverCertificate != null) { 157 + PrivateKey privateKey = (PrivateKey) this.contextS.getCtxServer().getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getBootstrapAlias(), this.contextS.getCtxServer().getKeyStorePasswordServer() == null ? null : this.contextS.getCtxServer().getKeyStorePasswordServer().toCharArray());
  158 + PublicKey publicKey = serverCertificate.getPublicKey();
  159 + if (serverCertificate != null &&
  160 + privateKey != null && privateKey.getEncoded().length > 0 &&
  161 + publicKey != null && publicKey.getEncoded().length > 0) {
  162 + builder.setPublicKey(serverCertificate.getPublicKey());
  163 + builder.setPrivateKey(privateKey);
247 builder.setCertificateChain(new X509Certificate[]{serverCertificate}); 164 builder.setCertificateChain(new X509Certificate[]{serverCertificate});
248 - this.infoParamsX509(serverCertificate); 165 + this.infoParamsServerX509(serverCertificate, publicKey, privateKey);
  166 + return true;
  167 + } else {
  168 + return false;
249 } 169 }
250 } catch (Exception ex) { 170 } catch (Exception ex) {
251 log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); 171 log.error("[{}] Unable to load KeyStore files server", ex.getMessage());
  172 + return false;
252 } 173 }
253 } 174 }
254 175
255 - private void getParamsRPK() {  
256 - if (this.publicKey instanceof ECPublicKey) {  
257 - /** Get x coordinate */  
258 - byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray();  
259 - if (x[0] == 0)  
260 - x = Arrays.copyOfRange(x, 1, x.length);  
261 -  
262 - /** Get Y coordinate */  
263 - byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray();  
264 - if (y[0] == 0)  
265 - y = Arrays.copyOfRange(y, 1, y.length);  
266 -  
267 - /** Get Curves params */  
268 - String params = ((ECPublicKey) this.publicKey).getParams().toString();  
269 - log.info(  
270 - " \nBootstrap uses RPK : \n Elliptic Curve parameters : [{}] \n Public x coord : [{}] \n Public y coord : [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]",  
271 - params, Hex.encodeHexString(x), Hex.encodeHexString(y),  
272 - Hex.encodeHexString(this.publicKey.getEncoded()),  
273 - Hex.encodeHexString(this.privateKey.getEncoded()));  
274 - } else {  
275 - throw new IllegalStateException("Unsupported Public Key Format (only ECPublicKey supported).");  
276 - }  
277 - }  
278 -  
279 - private void infoParamsX509(X509Certificate certificate) { 176 + private void infoParamsServerX509(X509Certificate certificate, PublicKey publicKey, PrivateKey privateKey) {
280 try { 177 try {
281 - log.info("BootStrap uses X509 : \n X509 Certificate (Hex): [{}] \n Private Key (Hex): [{}]", 178 + log.info("Bootstrap Server uses X509 : \n X509 Certificate (Hex): [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]",
282 Hex.encodeHexString(certificate.getEncoded()), 179 Hex.encodeHexString(certificate.getEncoded()),
283 - Hex.encodeHexString(this.privateKey.getEncoded())); 180 + Hex.encodeHexString(publicKey.getEncoded()),
  181 + Hex.encodeHexString(privateKey.getEncoded()));
284 } catch (CertificateEncodingException e) { 182 } catch (CertificateEncodingException e) {
285 log.error("", e); 183 log.error("", e);
286 } 184 }
287 } 185 }
288 186
  187 + private boolean setServerRPK(LeshanBootstrapServerBuilder builder) {
  188 + try {
  189 + this.generateKeyForBootstrapRPK();
  190 + if (this.publicKey != null && this.publicKey.getEncoded().length > 0 &&
  191 + this.privateKey != null && this.privateKey.getEncoded().length > 0) {
  192 + builder.setPublicKey(this.publicKey);
  193 + builder.setPrivateKey(this.privateKey);
  194 + return true;
  195 + }
  196 + } catch (NoSuchAlgorithmException | InvalidParameterSpecException | InvalidKeySpecException e) {
  197 + log.error("Fail create Bootstrap Server with RPK", e);
  198 + }
  199 + return false;
  200 + }
  201 +
  202 +
  203 + /**
  204 + * From yml^ bootstrap
  205 + * public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}"
  206 + * public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}"
  207 + * private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}"
  208 + */
  209 + private void generateKeyForBootstrapRPK() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException {
  210 + /** Get Elliptic Curve Parameter spec for secp256r1 */
  211 + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
  212 + algoParameters.init(new ECGenParameterSpec("secp256r1"));
  213 + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
  214 + if (this.contextBs.getCtxBootStrap().getBootstrapPublicX() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicX().isEmpty() && this.contextBs.getCtxBootStrap().getBootstrapPublicY() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicY().isEmpty()) {
  215 + /** Get point values */
  216 + byte[] publicX = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicX().toCharArray());
  217 + byte[] publicY = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicY().toCharArray());
  218 + /** Create key specs */
  219 + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
  220 + parameterSpec);
  221 + /** Get keys */
  222 + this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
  223 + }
  224 + if (this.contextBs.getCtxBootStrap().getBootstrapPrivateS() != null && !this.contextBs.getCtxBootStrap().getBootstrapPrivateS().isEmpty()) {
  225 + /** Get point values */
  226 + byte[] privateS = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPrivateS().toCharArray());
  227 + /** Create key specs */
  228 + KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec);
  229 + /** Get keys */
  230 + this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec);
  231 + }
  232 + }
  233 +
  234 + private void infoParamsServerRPK() {
  235 + /** Get x coordinate */
  236 + byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray();
  237 + if (x[0] == 0)
  238 + x = Arrays.copyOfRange(x, 1, x.length);
  239 +
  240 + /** Get Y coordinate */
  241 + byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray();
  242 + if (y[0] == 0)
  243 + y = Arrays.copyOfRange(y, 1, y.length);
  244 +
  245 + /** Get Curves params */
  246 + String params = ((ECPublicKey) this.publicKey).getParams().toString();
  247 + String privHex = Hex.encodeHexString(this.privateKey.getEncoded());
  248 + log.info("Server uses RPK -> serverNoSecureURI : [{}], serverSecureURI : [{}], \n" +
  249 + "Public Key (Hex): [{}] \n" +
  250 + "Private Key (Hex): [{}], \n" +
  251 + "- public_x : [{}] \n" +
  252 + "- public_y : [{}] \n" +
  253 + "- private_s : [{}] \n" +
  254 + "- Elliptic Curve parameters : [{}]",
  255 + this.contextBs.getCtxBootStrap().getBootstrapHost() + ":" + this.contextBs.getCtxBootStrap().getBootstrapPortNoSec(),
  256 + this.contextBs.getCtxBootStrap().getBootstrapHostSecurity() + ":" + this.contextBs.getCtxBootStrap().getBootstrapPortSecurity(),
  257 + Hex.encodeHexString(this.publicKey.getEncoded()),
  258 + Hex.encodeHexString(this.privateKey.getEncoded()),
  259 + Hex.encodeHexString(x),
  260 + Hex.encodeHexString(y),
  261 + privHex.substring(privHex.length() - 64),
  262 + params);
  263 + }
  264 +
  265 + private void infoParamsServerPSK() {
  266 + log.info("Server uses PSK -> serverNoSecureURI : [{}], serverSecureURI : [{}]",
  267 + this.contextBs.getCtxBootStrap().getBootstrapHost() + ":" + this.contextBs.getCtxBootStrap().getBootstrapPortNoSec(),
  268 + this.contextBs.getCtxBootStrap().getBootstrapHostSecurity() + ":" + this.contextBs.getCtxBootStrap().getBootstrapPortSecurity());
  269 + }
289 270
290 } 271 }
@@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.bootstrap; @@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.bootstrap;
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; 19 import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
20 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
21 -import org.springframework.beans.factory.annotation.Qualifier;  
22 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 21 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
23 import org.springframework.stereotype.Service; 22 import org.springframework.stereotype.Service;
24 23
@@ -31,39 +30,20 @@ import javax.annotation.PreDestroy; @@ -31,39 +30,20 @@ import javax.annotation.PreDestroy;
31 public class LwM2MTransportBootstrapServerInitializer { 30 public class LwM2MTransportBootstrapServerInitializer {
32 31
33 @Autowired(required = false) 32 @Autowired(required = false)
34 - @Qualifier("leshanBootstrapX509")  
35 - private LeshanBootstrapServer lhBServerCert;  
36 -  
37 - @Autowired(required = false)  
38 - @Qualifier("leshanBootstrapPsk")  
39 - private LeshanBootstrapServer lhBServerPsk;  
40 -  
41 - @Autowired(required = false)  
42 - @Qualifier("leshanBootstrapRpk")  
43 - private LeshanBootstrapServer lhBServerRpk; 33 + private LeshanBootstrapServer lhBServer;
44 34
45 @Autowired 35 @Autowired
46 private LwM2MTransportContextBootstrap contextBS; 36 private LwM2MTransportContextBootstrap contextBS;
47 37
48 @PostConstruct 38 @PostConstruct
49 public void init() { 39 public void init() {
50 - if (this.contextBS.getCtxBootStrap().getBootstrapStartPsk()) {  
51 - this.lhBServerPsk.start();  
52 - }  
53 - if (this.contextBS.getCtxBootStrap().getBootstrapStartRpk()) {  
54 - this.lhBServerRpk.start();  
55 - }  
56 - if (this.contextBS.getCtxBootStrap().getBootstrapStartX509()) {  
57 - this.lhBServerCert.start();  
58 - } 40 + this.lhBServer.start();
59 } 41 }
60 42
61 @PreDestroy 43 @PreDestroy
62 public void shutdown() throws InterruptedException { 44 public void shutdown() throws InterruptedException {
63 log.info("Stopping LwM2M transport Bootstrap Server!"); 45 log.info("Stopping LwM2M transport Bootstrap Server!");
64 - lhBServerPsk.destroy();  
65 - lhBServerRpk.destroy();  
66 - lhBServerCert.destroy(); 46 + lhBServer.destroy();
67 log.info("LwM2M transport Bootstrap Server stopped!"); 47 log.info("LwM2M transport Bootstrap Server stopped!");
68 } 48 }
69 } 49 }
@@ -25,31 +25,20 @@ import org.eclipse.leshan.server.californium.LeshanServer; @@ -25,31 +25,20 @@ import org.eclipse.leshan.server.californium.LeshanServer;
25 import org.eclipse.leshan.server.californium.LeshanServerBuilder; 25 import org.eclipse.leshan.server.californium.LeshanServerBuilder;
26 import org.eclipse.leshan.server.model.LwM2mModelProvider; 26 import org.eclipse.leshan.server.model.LwM2mModelProvider;
27 import org.eclipse.leshan.server.model.VersionedModelProvider; 27 import org.eclipse.leshan.server.model.VersionedModelProvider;
28 -import org.eclipse.leshan.server.redis.RedisRegistrationStore;  
29 -import org.eclipse.leshan.server.redis.RedisSecurityStore;  
30 import org.eclipse.leshan.server.security.DefaultAuthorizer; 28 import org.eclipse.leshan.server.security.DefaultAuthorizer;
31 -import org.eclipse.leshan.server.security.EditableSecurityStore;  
32 import org.eclipse.leshan.server.security.SecurityChecker; 29 import org.eclipse.leshan.server.security.SecurityChecker;
33 import org.springframework.beans.factory.annotation.Autowired; 30 import org.springframework.beans.factory.annotation.Autowired;
34 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 31 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
35 import org.springframework.context.annotation.Bean; 32 import org.springframework.context.annotation.Bean;
36 -import org.springframework.context.annotation.ComponentScan;  
37 -import org.springframework.context.annotation.Configuration;  
38 -import org.springframework.context.annotation.Primary;  
39 -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; 33 +import org.springframework.stereotype.Component;
40 import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; 34 import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore;
41 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 35 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
42 -import redis.clients.jedis.Jedis;  
43 -import redis.clients.jedis.JedisPool;  
44 -import redis.clients.jedis.util.Pool;  
45 36
46 import java.math.BigInteger; 37 import java.math.BigInteger;
47 -import java.net.URI;  
48 -import java.net.URISyntaxException;  
49 import java.security.AlgorithmParameters; 38 import java.security.AlgorithmParameters;
50 -import java.security.GeneralSecurityException;  
51 import java.security.KeyFactory; 39 import java.security.KeyFactory;
52 import java.security.KeyStoreException; 40 import java.security.KeyStoreException;
  41 +import java.security.NoSuchAlgorithmException;
53 import java.security.PrivateKey; 42 import java.security.PrivateKey;
54 import java.security.PublicKey; 43 import java.security.PublicKey;
55 import java.security.cert.CertificateEncodingException; 44 import java.security.cert.CertificateEncodingException;
@@ -60,20 +49,17 @@ import java.security.spec.ECParameterSpec; @@ -60,20 +49,17 @@ import java.security.spec.ECParameterSpec;
60 import java.security.spec.ECPoint; 49 import java.security.spec.ECPoint;
61 import java.security.spec.ECPrivateKeySpec; 50 import java.security.spec.ECPrivateKeySpec;
62 import java.security.spec.ECPublicKeySpec; 51 import java.security.spec.ECPublicKeySpec;
  52 +import java.security.spec.InvalidKeySpecException;
  53 +import java.security.spec.InvalidParameterSpecException;
63 import java.security.spec.KeySpec; 54 import java.security.spec.KeySpec;
64 import java.util.Arrays; 55 import java.util.Arrays;
65 56
  57 +import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
66 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; 58 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256;
67 -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.PSK;  
68 -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK;  
69 -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509;  
70 import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; 59 import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig;
71 60
72 -  
73 @Slf4j 61 @Slf4j
74 -@ComponentScan("org.thingsboard.server.transport.lwm2m.server")  
75 -@ComponentScan("org.thingsboard.server.transport.lwm2m.utils")  
76 -@Configuration("LwM2MTransportServerConfiguration") 62 +@Component("LwM2MTransportServerConfiguration")
77 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") 63 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
78 public class LwM2MTransportServerConfiguration { 64 public class LwM2MTransportServerConfiguration {
79 private PublicKey publicKey; 65 private PublicKey publicKey;
@@ -85,32 +71,16 @@ public class LwM2MTransportServerConfiguration { @@ -85,32 +71,16 @@ public class LwM2MTransportServerConfiguration {
85 @Autowired 71 @Autowired
86 private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; 72 private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore;
87 73
88 - @Primary  
89 - @Bean(name = "leshanServerPsk")  
90 - @ConditionalOnExpression("('${transport.lwm2m.server.secure.start_psk:false}'=='true')")  
91 - public LeshanServer getLeshanServerPsk() {  
92 - log.info("Starting LwM2M transport ServerPsk... PostConstruct");  
93 - return getLeshanServer(this.context.getCtxServer().getServerPortNoSecPsk(), this.context.getCtxServer().getServerPortPsk(), PSK);  
94 - }  
95 -  
96 - @Bean(name = "leshanServerRpk")  
97 - @ConditionalOnExpression("('${transport.lwm2m.server.secure.start_rpk:false}'=='true')")  
98 - public LeshanServer getLeshanServerRpk() {  
99 - log.info("Starting LwM2M transport ServerRpk... PostConstruct");  
100 - return getLeshanServer(this.context.getCtxServer().getServerPortNoSecRpk(), this.context.getCtxServer().getServerPortRpk(), RPK);  
101 - }  
102 -  
103 - @Bean(name = "leshanServerX509")  
104 - @ConditionalOnExpression("('${transport.lwm2m.server.secure.start_x509:false}'=='true')")  
105 - public LeshanServer getLeshanServerX509() {  
106 - log.info("Starting LwM2M transport ServerX509... PostConstruct");  
107 - return getLeshanServer(this.context.getCtxServer().getServerPortNoSecX509(), this.context.getCtxServer().getServerPortX509(), X509); 74 + @Bean
  75 + public LeshanServer getLeshanServer() {
  76 + log.info("Starting LwM2M transport Server... PostConstruct");
  77 + return this.getLhServer(this.context.getCtxServer().getServerPortNoSec(), this.context.getCtxServer().getServerPortSecurity());
108 } 78 }
109 79
110 - private LeshanServer getLeshanServer(Integer serverPortNoSec, Integer serverSecurePort, LwM2MSecurityMode dtlsMode) { 80 + private LeshanServer getLhServer(Integer serverPortNoSec, Integer serverSecurePort) {
111 LeshanServerBuilder builder = new LeshanServerBuilder(); 81 LeshanServerBuilder builder = new LeshanServerBuilder();
112 builder.setLocalAddress(this.context.getCtxServer().getServerHost(), serverPortNoSec); 82 builder.setLocalAddress(this.context.getCtxServer().getServerHost(), serverPortNoSec);
113 - builder.setLocalSecureAddress(this.context.getCtxServer().getServerSecureHost(), serverSecurePort); 83 + builder.setLocalSecureAddress(this.context.getCtxServer().getServerHostSecurity(), serverSecurePort);
114 builder.setEncoder(new DefaultLwM2mNodeEncoder()); 84 builder.setEncoder(new DefaultLwM2mNodeEncoder());
115 LwM2mNodeDecoder decoder = new DefaultLwM2mNodeDecoder(); 85 LwM2mNodeDecoder decoder = new DefaultLwM2mNodeDecoder();
116 builder.setDecoder(decoder); 86 builder.setDecoder(decoder);
@@ -123,22 +93,19 @@ public class LwM2MTransportServerConfiguration { @@ -123,22 +93,19 @@ public class LwM2MTransportServerConfiguration {
123 LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getCtxServer().getModelsValue()); 93 LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getCtxServer().getModelsValue());
124 builder.setObjectModelProvider(modelProvider); 94 builder.setObjectModelProvider(modelProvider);
125 95
126 - /** Create DTLS security mode  
127 - * There can be only one DTLS security mode  
128 - */  
129 - this.LwM2MSetSecurityStoreServer(builder, dtlsMode); 96 + /** Create credentials */
  97 + this.setServerWithCredentials(builder);
  98 +
  99 + /** Set securityStore with new registrationStore */
  100 + builder.setSecurityStore(lwM2mInMemorySecurityStore);
  101 +
130 102
131 /** Create DTLS Config */ 103 /** Create DTLS Config */
132 DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); 104 DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
133 - if (dtlsMode==PSK) {  
134 - dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getCtxServer().isRecommendedCiphers());  
135 - dtlsConfig.setRecommendedSupportedGroupsOnly(this.context.getCtxServer().isRecommendedSupportedGroups());  
136 - dtlsConfig.setSupportedCipherSuites(TLS_PSK_WITH_AES_128_CBC_SHA256);  
137 - }  
138 - else {  
139 - dtlsConfig.setRecommendedSupportedGroupsOnly(!this.context.getCtxServer().isRecommendedSupportedGroups());  
140 - dtlsConfig.setRecommendedCipherSuitesOnly(!this.context.getCtxServer().isRecommendedCiphers());  
141 - } 105 + dtlsConfig.setRecommendedSupportedGroupsOnly(!this.context.getCtxServer().isRecommendedSupportedGroups());
  106 + dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getCtxServer().isRecommendedCiphers());
  107 + dtlsConfig.setSupportedCipherSuites(TLS_PSK_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256);
  108 +
142 /** Set DTLS Config */ 109 /** Set DTLS Config */
143 builder.setDtlsConfig(dtlsConfig); 110 builder.setDtlsConfig(dtlsConfig);
144 111
@@ -150,154 +117,42 @@ public class LwM2MTransportServerConfiguration { @@ -150,154 +117,42 @@ public class LwM2MTransportServerConfiguration {
150 return builder.build(); 117 return builder.build();
151 } 118 }
152 119
153 - private void LwM2MSetSecurityStoreServer(LeshanServerBuilder builder, LwM2MSecurityMode dtlsMode) {  
154 - /** Set securityStore with new registrationStore */  
155 - EditableSecurityStore securityStore = lwM2mInMemorySecurityStore;  
156 - switch (dtlsMode) {  
157 - /** Use PSK only */  
158 - case PSK:  
159 - generatePSK_RPK();  
160 - infoParamsPSK();  
161 - break;  
162 - /** Use RPK only */  
163 - case RPK:  
164 - generatePSK_RPK();  
165 - if (this.publicKey != null && this.publicKey.getEncoded().length > 0 &&  
166 - this.privateKey != null && this.privateKey.getEncoded().length > 0) {  
167 - builder.setPublicKey(this.publicKey);  
168 - builder.setPrivateKey(this.privateKey);  
169 - infoParamsRPK();  
170 - }  
171 - break;  
172 - /** Use x509 only */  
173 - case X509:  
174 - setServerWithX509Cert(builder);  
175 - break;  
176 - /** No security */  
177 - case NO_SEC:  
178 - builder.setTrustedCertificates(new X509Certificate[0]);  
179 - break;  
180 - /** Use x509 with EST */  
181 - case X509_EST:  
182 - // TODO support sentinel pool and make pool configurable  
183 - break;  
184 - case REDIS:  
185 - /**  
186 - * Set securityStore with new registrationStore (if use redis store)  
187 - * Connect to redis  
188 - */  
189 - Pool<Jedis> jedis = null;  
190 - try {  
191 - jedis = new JedisPool(new URI(this.context.getCtxServer().getRedisUrl()));  
192 - securityStore = new RedisSecurityStore(jedis);  
193 - builder.setRegistrationStore(new RedisRegistrationStore(jedis));  
194 - } catch (URISyntaxException e) {  
195 - log.error("", e);  
196 - }  
197 - break;  
198 - default:  
199 - }  
200 -  
201 - /** Set securityStore with registrationStore (if x509)*/  
202 - if (dtlsMode == X509) {  
203 - builder.setAuthorizer(new DefaultAuthorizer(securityStore, new SecurityChecker() {  
204 - @Override  
205 - protected boolean matchX509Identity(String endpoint, String receivedX509CommonName,  
206 - String expectedX509CommonName) {  
207 - return endpoint.startsWith(expectedX509CommonName);  
208 - }  
209 - }));  
210 - }  
211 -  
212 - /** Set securityStore with new registrationStore */  
213 - builder.setSecurityStore(securityStore);  
214 - }  
215 -  
216 - private void generatePSK_RPK() {  
217 - try {  
218 - /** Get Elliptic Curve Parameter spec for secp256r1 */  
219 - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");  
220 - algoParameters.init(new ECGenParameterSpec("secp256r1"));  
221 - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);  
222 - if (this.context.getCtxServer().getServerPublicX() != null && !this.context.getCtxServer().getServerPublicX().isEmpty() && this.context.getCtxServer().getServerPublicY() != null && !this.context.getCtxServer().getServerPublicY().isEmpty()) {  
223 - /** Get point values */  
224 - byte[] publicX = Hex.decodeHex(this.context.getCtxServer().getServerPublicX().toCharArray());  
225 - byte[] publicY = Hex.decodeHex(this.context.getCtxServer().getServerPublicY().toCharArray());  
226 - /** Create key specs */  
227 - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),  
228 - parameterSpec);  
229 - /** Get keys */  
230 - this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);  
231 - }  
232 - if (this.context.getCtxServer().getServerPrivateS() != null && !this.context.getCtxServer().getServerPrivateS().isEmpty()) {  
233 - /** Get point values */  
234 - byte[] privateS = Hex.decodeHex(this.context.getCtxServer().getServerPrivateS().toCharArray());  
235 - /** Create key specs */  
236 - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec);  
237 - /** Get keys */  
238 - this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec);  
239 - }  
240 - } catch (GeneralSecurityException | IllegalArgumentException e) {  
241 - log.error("[{}] Failed generate Server PSK/RPK", e.getMessage());  
242 - throw new RuntimeException(e);  
243 - }  
244 - }  
245 -  
246 - private void infoParamsPSK() {  
247 - log.info("\nServer uses PSK -> private key : \n security key : [{}] \n serverSecureURI : [{}]",  
248 - Hex.encodeHexString(this.privateKey.getEncoded()),  
249 - this.context.getCtxServer().getServerSecureHost() + ":" + Integer.toString(this.context.getCtxServer().getServerPortPsk()));  
250 - }  
251 -  
252 - private void infoParamsRPK() {  
253 - if (this.publicKey instanceof ECPublicKey) {  
254 - /** Get x coordinate */  
255 - byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray();  
256 - if (x[0] == 0)  
257 - x = Arrays.copyOfRange(x, 1, x.length);  
258 -  
259 - /** Get Y coordinate */  
260 - byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray();  
261 - if (y[0] == 0)  
262 - y = Arrays.copyOfRange(y, 1, y.length);  
263 -  
264 - /** Get Curves params */  
265 - String params = ((ECPublicKey) this.publicKey).getParams().toString();  
266 - log.info(  
267 - " \nServer uses RPK : \n Elliptic Curve parameters : [{}] \n Public x coord : [{}] \n Public y coord : [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]",  
268 - params, Hex.encodeHexString(x), Hex.encodeHexString(y),  
269 - Hex.encodeHexString(this.publicKey.getEncoded()),  
270 - Hex.encodeHexString(this.privateKey.getEncoded()));  
271 - } else {  
272 - throw new IllegalStateException("Unsupported Public Key Format (only ECPublicKey supported).");  
273 - }  
274 - }  
275 -  
276 -  
277 - private void setServerWithX509Cert(LeshanServerBuilder builder) { 120 + private void setServerWithCredentials(LeshanServerBuilder builder) {
278 try { 121 try {
279 if (this.context.getCtxServer().getKeyStoreValue() != null) { 122 if (this.context.getCtxServer().getKeyStoreValue() != null) {
280 - setBuilderX509(builder);  
281 - X509Certificate rootCAX509Cert = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getRootAlias());  
282 - if (rootCAX509Cert != null) {  
283 - X509Certificate[] trustedCertificates = new X509Certificate[1];  
284 - trustedCertificates[0] = rootCAX509Cert;  
285 - builder.setTrustedCertificates(trustedCertificates); 123 + if (this.setBuilderX509(builder)) {
  124 + X509Certificate rootCAX509Cert = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getRootAlias());
  125 + if (rootCAX509Cert != null) {
  126 + X509Certificate[] trustedCertificates = new X509Certificate[1];
  127 + trustedCertificates[0] = rootCAX509Cert;
  128 + builder.setTrustedCertificates(trustedCertificates);
  129 + } else {
  130 + /** by default trust all */
  131 + builder.setTrustedCertificates(new X509Certificate[0]);
  132 + }
  133 + /** Set securityStore with registrationStore*/
  134 + builder.setAuthorizer(new DefaultAuthorizer(lwM2mInMemorySecurityStore, new SecurityChecker() {
  135 + @Override
  136 + protected boolean matchX509Identity(String endpoint, String receivedX509CommonName,
  137 + String expectedX509CommonName) {
  138 + return endpoint.startsWith(expectedX509CommonName);
  139 + }
  140 + }));
  141 + } else if (this.setServerRPK(builder)) {
  142 + this.infoParamsServerRPK();
286 } else { 143 } else {
287 /** by default trust all */ 144 /** by default trust all */
288 builder.setTrustedCertificates(new X509Certificate[0]); 145 builder.setTrustedCertificates(new X509Certificate[0]);
  146 + log.info("Unable to load X509 files for LWM2MServer");
  147 + this.infoParamsServerPSK();
289 } 148 }
290 - } else {  
291 - /** by default trust all */  
292 - builder.setTrustedCertificates(new X509Certificate[0]);  
293 - log.error("Unable to load X509 files for LWM2MServer");  
294 } 149 }
295 } catch (KeyStoreException ex) { 150 } catch (KeyStoreException ex) {
296 log.error("[{}] Unable to load X509 files server", ex.getMessage()); 151 log.error("[{}] Unable to load X509 files server", ex.getMessage());
297 } 152 }
298 } 153 }
299 154
300 - private void setBuilderX509(LeshanServerBuilder builder) { 155 + private boolean setBuilderX509(LeshanServerBuilder builder) {
301 /** 156 /**
302 * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE 157 * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE
303 * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks 158 * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks
@@ -305,38 +160,122 @@ public class LwM2MTransportServerConfiguration { @@ -305,38 +160,122 @@ public class LwM2MTransportServerConfiguration {
305 try { 160 try {
306 X509Certificate serverCertificate = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getServerAlias()); 161 X509Certificate serverCertificate = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getServerAlias());
307 PrivateKey privateKey = (PrivateKey) this.context.getCtxServer().getKeyStoreValue().getKey(this.context.getCtxServer().getServerAlias(), this.context.getCtxServer().getKeyStorePasswordServer() == null ? null : this.context.getCtxServer().getKeyStorePasswordServer().toCharArray()); 162 PrivateKey privateKey = (PrivateKey) this.context.getCtxServer().getKeyStoreValue().getKey(this.context.getCtxServer().getServerAlias(), this.context.getCtxServer().getKeyStorePasswordServer() == null ? null : this.context.getCtxServer().getKeyStorePasswordServer().toCharArray());
308 - builder.setPrivateKey(privateKey);  
309 - builder.setCertificateChain(new X509Certificate[]{serverCertificate});  
310 - this.infoParamsX509(serverCertificate, privateKey); 163 + PublicKey publicKey = serverCertificate.getPublicKey();
  164 + if (serverCertificate != null &&
  165 + privateKey != null && privateKey.getEncoded().length > 0 &&
  166 + publicKey != null && publicKey.getEncoded().length > 0) {
  167 + builder.setPublicKey(serverCertificate.getPublicKey());
  168 + builder.setPrivateKey(privateKey);
  169 + builder.setCertificateChain(new X509Certificate[]{serverCertificate});
  170 + this.infoParamsServerX509(serverCertificate, publicKey, privateKey);
  171 + return true;
  172 + }
  173 + else {
  174 + return false;
  175 + }
311 } catch (Exception ex) { 176 } catch (Exception ex) {
312 log.error("[{}] Unable to load KeyStore files server", ex.getMessage()); 177 log.error("[{}] Unable to load KeyStore files server", ex.getMessage());
  178 + return false;
313 } 179 }
314 -// /**  
315 -// * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE  
316 -// * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks  
317 -// */  
318 -// try {  
319 -// X509Certificate serverCertificate = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getServerPrivateS());  
320 -// this.privateKey = (PrivateKey) this.context.getCtxServer().getKeyStoreValue().getKey(this.context.getCtxServer().getServerAlias(), this.context.getCtxServer().getKeyStorePasswordServer() == null ? null : this.context.getCtxServer().getKeyStorePasswordServer().toCharArray());  
321 -// if (this.privateKey != null && this.privateKey.getEncoded().length > 0) {  
322 -// builder.setPrivateKey(this.privateKey);  
323 -// }  
324 -// if (serverCertificate != null) {  
325 -// builder.setCertificateChain(new X509Certificate[]{serverCertificate});  
326 -// this.infoParamsX509(serverCertificate);  
327 -// }  
328 -// } catch (Exception ex) {  
329 -// log.error("[{}] Unable to load KeyStore files server", ex.getMessage());  
330 -// }  
331 } 180 }
332 181
333 - private void infoParamsX509(X509Certificate certificate, PrivateKey privateKey) { 182 + private void infoParamsServerX509(X509Certificate certificate, PublicKey publicKey, PrivateKey privateKey) {
334 try { 183 try {
335 - log.info("Server uses X509 : \n X509 Certificate (Hex): [{}] \n Private Key (Hex): [{}]", 184 + log.info("Server uses X509 : \n X509 Certificate (Hex): [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]",
336 Hex.encodeHexString(certificate.getEncoded()), 185 Hex.encodeHexString(certificate.getEncoded()),
  186 + Hex.encodeHexString(publicKey.getEncoded()),
337 Hex.encodeHexString(privateKey.getEncoded())); 187 Hex.encodeHexString(privateKey.getEncoded()));
338 } catch (CertificateEncodingException e) { 188 } catch (CertificateEncodingException e) {
339 log.error("", e); 189 log.error("", e);
340 } 190 }
341 } 191 }
  192 +
  193 + private boolean setServerRPK(LeshanServerBuilder builder) {
  194 + try {
  195 + this.generateKeyForRPK();
  196 + if (this.publicKey != null && this.publicKey.getEncoded().length > 0 &&
  197 + this.privateKey != null && this.privateKey.getEncoded().length > 0) {
  198 + builder.setPublicKey(this.publicKey);
  199 + builder.setPrivateKey(this.privateKey);
  200 + return true;
  201 + }
  202 + } catch (NoSuchAlgorithmException | InvalidParameterSpecException | InvalidKeySpecException e) {
  203 + log.error("Fail create Server with RPK", e);
  204 + }
  205 + return false;
  206 + }
  207 +
  208 +
  209 + /**
  210 + * From yml^ server
  211 + * public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}"
  212 + * public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}"
  213 + * private_s: "${LWM2M_SERVER_PRIVATE_S:274671fe40ce937b8a6352cf0a418e8a39e4bf0bb9bf74c910db953c20c73802}"
  214 + */
  215 + private void generateKeyForRPK() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException {
  216 + /** Get Elliptic Curve Parameter spec for secp256r1 */
  217 + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
  218 + algoParameters.init(new ECGenParameterSpec("secp256r1"));
  219 + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
  220 + if (this.context.getCtxServer().getServerPublicX() != null &&
  221 + !this.context.getCtxServer().getServerPublicX().isEmpty() &&
  222 + this.context.getCtxServer().getServerPublicY() != null &&
  223 + !this.context.getCtxServer().getServerPublicY().isEmpty()) {
  224 + /** Get point values */
  225 + byte[] publicX = Hex.decodeHex(this.context.getCtxServer().getServerPublicX().toCharArray());
  226 + byte[] publicY = Hex.decodeHex(this.context.getCtxServer().getServerPublicY().toCharArray());
  227 + /** Create key specs */
  228 + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
  229 + parameterSpec);
  230 + /** Get keys */
  231 + this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
  232 + }
  233 + if (this.context.getCtxServer().getServerPrivateS() != null &&
  234 + !this.context.getCtxServer().getServerPrivateS().isEmpty()) {
  235 + /** Get point values */
  236 + byte[] privateS = Hex.decodeHex(this.context.getCtxServer().getServerPrivateS().toCharArray());
  237 + /** Create key specs */
  238 + KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec);
  239 + /** Get keys */
  240 + this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec);
  241 + }
  242 + }
  243 +
  244 + private void infoParamsServerRPK() {
  245 + /** Get x coordinate */
  246 + byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray();
  247 + if (x[0] == 0)
  248 + x = Arrays.copyOfRange(x, 1, x.length);
  249 +
  250 + /** Get Y coordinate */
  251 + byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray();
  252 + if (y[0] == 0)
  253 + y = Arrays.copyOfRange(y, 1, y.length);
  254 +
  255 + /** Get Curves params */
  256 + String params = ((ECPublicKey) this.publicKey).getParams().toString();
  257 + String privHex = Hex.encodeHexString(this.privateKey.getEncoded());
  258 + log.info("Server uses RPK -> serverNoSecureURI : [{}], serverSecureURI : [{}], \n" +
  259 + "Public Key (Hex): [{}] \n" +
  260 + "Private Key (Hex): [{}], \n" +
  261 + "- public_x : [{}] \n" +
  262 + "- public_y : [{}] \n" +
  263 + "- private_s : [{}] \n" +
  264 + "- Elliptic Curve parameters : [{}]",
  265 + this.context.getCtxServer().getServerHost() + ":" + this.context.getCtxServer().getServerPortNoSec(),
  266 + this.context.getCtxServer().getServerHostSecurity() + ":" + this.context.getCtxServer().getServerPortSecurity(),
  267 + Hex.encodeHexString(this.publicKey.getEncoded()),
  268 + Hex.encodeHexString(this.privateKey.getEncoded()),
  269 + Hex.encodeHexString(x),
  270 + Hex.encodeHexString(y),
  271 + privHex.substring(privHex.length() - 64),
  272 + params);
  273 + }
  274 +
  275 + private void infoParamsServerPSK() {
  276 + log.info("Server uses PSK -> serverNoSecureURI : [{}], serverSecureURI : [{}]",
  277 + this.context.getCtxServer().getServerHost() + ":" + Integer.toString(this.context.getCtxServer().getServerPortNoSec()),
  278 + this.context.getCtxServer().getServerHostSecurity() + ":" + Integer.toString(this.context.getCtxServer().getServerPortSecurity()));
  279 + }
  280 +
342 } 281 }
@@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server; @@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server;
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.leshan.server.californium.LeshanServer; 19 import org.eclipse.leshan.server.californium.LeshanServer;
20 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
21 -import org.springframework.beans.factory.annotation.Qualifier;  
22 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 21 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
23 import org.springframework.stereotype.Component; 22 import org.springframework.stereotype.Component;
24 import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; 23 import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC;
@@ -31,69 +30,35 @@ import javax.annotation.PreDestroy; @@ -31,69 +30,35 @@ import javax.annotation.PreDestroy;
31 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") 30 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
32 public class LwM2MTransportServerInitializer { 31 public class LwM2MTransportServerInitializer {
33 32
34 -  
35 @Autowired 33 @Autowired
36 private LwM2MTransportServiceImpl service; 34 private LwM2MTransportServiceImpl service;
37 35
38 @Autowired(required = false) 36 @Autowired(required = false)
39 - @Qualifier("leshanServerX509")  
40 - private LeshanServer lhServerX509;  
41 -  
42 - @Autowired(required = false)  
43 - @Qualifier("leshanServerPsk")  
44 - private LeshanServer lhServerPsk;  
45 -  
46 - @Autowired(required = false)  
47 - @Qualifier("leshanServerRpk")  
48 - private LeshanServer lhServerRpk; 37 + private LeshanServer leshanServer;
49 38
50 @Autowired 39 @Autowired
51 private LwM2MTransportContextServer context; 40 private LwM2MTransportContextServer context;
52 41
53 @PostConstruct 42 @PostConstruct
54 public void init() { 43 public void init() {
55 - if (this.context.getCtxServer().getEnableGenPskRpk()) new LWM2MGenerationPSkRPkECC();  
56 - if (this.context.getCtxServer().isServerStartPsk()) {  
57 - this.startLhServerPsk();  
58 - }  
59 - if (this.context.getCtxServer().isServerStartRpk()) {  
60 - this.startLhServerRpk(); 44 + if (this.context.getCtxServer().getEnableGenPskRpk()) {
  45 + new LWM2MGenerationPSkRPkECC();
61 } 46 }
62 - if (this.context.getCtxServer().isServerStartX509()) {  
63 - this.startLhServerX509();  
64 - }  
65 - }  
66 -  
67 - private void startLhServerPsk() {  
68 - this.lhServerPsk.start();  
69 - LwM2mServerListener lhServerPskListener = new LwM2mServerListener(this.lhServerPsk, service);  
70 - this.lhServerPsk.getRegistrationService().addListener(lhServerPskListener.registrationListener);  
71 - this.lhServerPsk.getPresenceService().addListener(lhServerPskListener.presenceListener);  
72 - this.lhServerPsk.getObservationService().addListener(lhServerPskListener.observationListener);  
73 - }  
74 -  
75 - private void startLhServerRpk() {  
76 - this.lhServerRpk.start();  
77 - LwM2mServerListener lhServerRpkListener = new LwM2mServerListener(this.lhServerRpk, service);  
78 - this.lhServerRpk.getRegistrationService().addListener(lhServerRpkListener.registrationListener);  
79 - this.lhServerRpk.getPresenceService().addListener(lhServerRpkListener.presenceListener);  
80 - this.lhServerRpk.getObservationService().addListener(lhServerRpkListener.observationListener); 47 + this.startLhServer();
81 } 48 }
82 49
83 - private void startLhServerX509() {  
84 - this.lhServerX509.start();  
85 - LwM2mServerListener lhServerCertListener = new LwM2mServerListener(this.lhServerX509, service);  
86 - this.lhServerX509.getRegistrationService().addListener(lhServerCertListener.registrationListener);  
87 - this.lhServerX509.getPresenceService().addListener(lhServerCertListener.presenceListener);  
88 - this.lhServerX509.getObservationService().addListener(lhServerCertListener.observationListener); 50 + private void startLhServer() {
  51 + this.leshanServer.start();
  52 + LwM2mServerListener lhServerCertListener = new LwM2mServerListener(this.leshanServer, service);
  53 + this.leshanServer.getRegistrationService().addListener(lhServerCertListener.registrationListener);
  54 + this.leshanServer.getPresenceService().addListener(lhServerCertListener.presenceListener);
  55 + this.leshanServer.getObservationService().addListener(lhServerCertListener.observationListener);
89 } 56 }
90 57
91 @PreDestroy 58 @PreDestroy
92 public void shutdown() { 59 public void shutdown() {
93 log.info("Stopping LwM2M transport Server!"); 60 log.info("Stopping LwM2M transport Server!");
94 - lhServerPsk.destroy();  
95 - lhServerRpk.destroy();  
96 - lhServerX509.destroy(); 61 + leshanServer.destroy();
97 log.info("LwM2M transport Server stopped!"); 62 log.info("LwM2M transport Server stopped!");
98 } 63 }
99 } 64 }
@@ -40,48 +40,20 @@ public class LwM2MTransportConfigBootstrap { @@ -40,48 +40,20 @@ public class LwM2MTransportConfigBootstrap {
40 private Integer bootstrapServerId; 40 private Integer bootstrapServerId;
41 41
42 @Getter 42 @Getter
43 - @Value("${transport.lwm2m.bootstrap.secure.start_psk:}")  
44 - private Boolean bootstrapStartPsk;  
45 -  
46 - @Getter  
47 - @Value("${transport.lwm2m.bootstrap.secure.start_rpk:}")  
48 - private Boolean bootstrapStartRpk;  
49 -  
50 - @Getter  
51 - @Value("${transport.lwm2m.bootstrap.secure.start_x509:}")  
52 - private Boolean bootstrapStartX509;  
53 -  
54 - @Getter  
55 @Value("${transport.lwm2m.bootstrap.bind_address:}") 43 @Value("${transport.lwm2m.bootstrap.bind_address:}")
56 private String bootstrapHost; 44 private String bootstrapHost;
57 45
58 @Getter 46 @Getter
59 - @Value("${transport.lwm2m.bootstrap.secure.bind_address:}")  
60 - private String bootstrapSecureHost;  
61 -  
62 - @Getter  
63 - @Value("${transport.lwm2m.bootstrap.bind_port_no_sec_psk:}")  
64 - private Integer bootstrapPortNoSecPsk;  
65 -  
66 - @Getter  
67 - @Value("${transport.lwm2m.bootstrap.bind_port_no_sec_rpk:}")  
68 - private Integer bootstrapPortNoSecRpk;  
69 -  
70 - @Getter  
71 - @Value("${transport.lwm2m.bootstrap.bind_port_no_sec_x509:}")  
72 - private Integer bootstrapPortNoSecX509;  
73 -  
74 - @Getter  
75 - @Value("${transport.lwm2m.bootstrap.secure.bind_port_psk:}")  
76 - private Integer bootstrapSecurePortPsk; 47 + @Value("${transport.lwm2m.bootstrap.bind_port_no_sec:}")
  48 + private Integer bootstrapPortNoSec;
77 49
78 @Getter 50 @Getter
79 - @Value("${transport.lwm2m.bootstrap.secure.bind_port_rpk:}")  
80 - private Integer bootstrapSecurePortRpk; 51 + @Value("${transport.lwm2m.bootstrap.secure.bind_address_security:}")
  52 + private String bootstrapHostSecurity;
81 53
82 @Getter 54 @Getter
83 - @Value("${transport.lwm2m.bootstrap.secure.bind_port_x509:}")  
84 - private Integer bootstrapSecurePortX509; 55 + @Value("${transport.lwm2m.bootstrap.secure.bind_port_security:}")
  56 + private Integer bootstrapPortSecurity;
85 57
86 @Getter 58 @Getter
87 @Value("${transport.lwm2m.bootstrap.secure.public_x:}") 59 @Value("${transport.lwm2m.bootstrap.secure.public_x:}")
@@ -79,7 +79,7 @@ public class LwM2MTransportConfigServer { @@ -79,7 +79,7 @@ public class LwM2MTransportConfigServer {
79 private String BASE_DIR_PATH = System.getProperty("user.dir"); 79 private String BASE_DIR_PATH = System.getProperty("user.dir");
80 80
81 @Getter 81 @Getter
82 -// private String PATH_DATA_MICROSERVICE = "/usr/share/tb-lwm2m-transport/data$"; 82 + // private String PATH_DATA_MICROSERVICE = "/usr/share/tb-lwm2m-transport/data$";
83 private String PATH_DATA = "data"; 83 private String PATH_DATA = "data";
84 84
85 @Getter 85 @Getter
@@ -147,57 +147,28 @@ public class LwM2MTransportConfigServer { @@ -147,57 +147,28 @@ public class LwM2MTransportConfigServer {
147 private String rootAlias; 147 private String rootAlias;
148 148
149 @Getter 149 @Getter
150 - @Value("${transport.lwm2m.server.secure.start_psk:}")  
151 - private boolean serverStartPsk;  
152 -  
153 - @Getter  
154 - @Value("${transport.lwm2m.server.secure.start_rpk:}")  
155 - private boolean serverStartRpk;  
156 -  
157 - @Getter  
158 - @Value("${transport.lwm2m.server.secure.start_x509:}")  
159 - private boolean serverStartX509;  
160 -  
161 - @Getter  
162 @Value("${transport.lwm2m.secure.enable_gen_psk_rpk:}") 150 @Value("${transport.lwm2m.secure.enable_gen_psk_rpk:}")
163 private Boolean enableGenPskRpk; 151 private Boolean enableGenPskRpk;
164 152
165 @Getter 153 @Getter
166 - @Value("${transport.lwm2m.server.bind_address:}")  
167 - private String serverHost;  
168 -  
169 - @Getter  
170 @Value("${transport.lwm2m.server.id:}") 154 @Value("${transport.lwm2m.server.id:}")
171 private Integer serverId; 155 private Integer serverId;
172 156
173 @Getter 157 @Getter
174 - @Value("${transport.lwm2m.server.secure.bind_address:}")  
175 - private String serverSecureHost;  
176 -  
177 -  
178 - @Getter  
179 - @Value("${transport.lwm2m.server.bind_port_no_sec_psk:}")  
180 - private Integer serverPortNoSecPsk;  
181 -  
182 - @Getter  
183 - @Value("${transport.lwm2m.server.bind_port_no_sec_rpk:}")  
184 - private Integer serverPortNoSecRpk;  
185 -  
186 - @Getter  
187 - @Value("${transport.lwm2m.server.bind_port_no_sec_x509:}")  
188 - private Integer serverPortNoSecX509; 158 + @Value("${transport.lwm2m.server.bind_address:}")
  159 + private String serverHost;
189 160
190 @Getter 161 @Getter
191 - @Value("${transport.lwm2m.server.secure.bind_port_psk:}")  
192 - private Integer serverPortPsk; 162 + @Value("${transport.lwm2m.server.secure.bind_address_security:}")
  163 + private String serverHostSecurity;
193 164
194 @Getter 165 @Getter
195 - @Value("${transport.lwm2m.server.secure.bind_port_rpk:}")  
196 - private Integer serverPortRpk; 166 + @Value("${transport.lwm2m.server.bind_port_no_sec:}")
  167 + private Integer serverPortNoSec;
197 168
198 @Getter 169 @Getter
199 - @Value("${transport.lwm2m.server.secure.bind_port_x509:}")  
200 - private Integer serverPortX509; 170 + @Value("${transport.lwm2m.server.secure.bind_port_security:}")
  171 + private Integer serverPortSecurity;
201 172
202 @Getter 173 @Getter
203 @Value("${transport.lwm2m.server.secure.public_x:}") 174 @Value("${transport.lwm2m.server.secure.public_x:}")
@@ -303,7 +274,4 @@ public class LwM2MTransportConfigServer { @@ -303,7 +274,4 @@ public class LwM2MTransportConfigServer {
303 ResourceModel resource = this.getResourceModel(registration, pathIds); 274 ResourceModel resource = this.getResourceModel(registration, pathIds);
304 return (resource == null) ? ResourceModel.Operations.NONE : resource.operations; 275 return (resource == null) ? ResourceModel.Operations.NONE : resource.operations;
305 } 276 }
306 -  
307 -  
308 -  
309 } 277 }
@@ -60,7 +60,7 @@ transport: @@ -60,7 +60,7 @@ transport:
60 update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}" 60 update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}"
61 un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}" 61 un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}"
62 secure: 62 secure:
63 - # Only Certificate_x509: 63 + # Certificate_x509:
64 # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format 64 # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
65 # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh 65 # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
66 key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}" 66 key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
@@ -73,18 +73,11 @@ transport: @@ -73,18 +73,11 @@ transport:
73 server: 73 server:
74 id: "${LWM2M_SERVER_ID:123}" 74 id: "${LWM2M_SERVER_ID:123}"
75 bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" 75 bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}"
76 - bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_PSK:5685}"  
77 - bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_RPK:5687}"  
78 - bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_X509:5689}" 76 + bind_port_no_sec: "${LWM2M_BIND_PORT_NO_SEC:5685}"
79 secure: 77 secure:
80 - bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}"  
81 - start_psk: "${START_SERVER_PSK:true}"  
82 - start_rpk: "${START_SERVER_RPK:true}"  
83 - start_x509: "${START_SERVER_X509:true}"  
84 - bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK:5686}"  
85 - bind_port_rpk: "${LWM2M_BIND_PORT_SEC_RPK:5688}"  
86 - bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509:5690}"  
87 - # Only RPK: Public & Private Key 78 + bind_address_security: "${LWM2M_BIND_ADDRESS_SECURITY:0.0.0.0}"
  79 + bind_port_security: "${LWM2M_BIND_PORT_SECURITY:5686}"
  80 + # Only for RPK: Public & Private Key. If the keystore file is missing or not working
88 # create_rpk: "${CREATE_RPK:}" 81 # create_rpk: "${CREATE_RPK:}"
89 public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}" 82 public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}"
90 public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}" 83 public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}"
@@ -92,28 +85,22 @@ transport: @@ -92,28 +85,22 @@ transport:
92 # Only Certificate_x509: 85 # Only Certificate_x509:
93 alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}" 86 alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}"
94 bootstrap: 87 bootstrap:
95 - enable: "${BOOTSTRAP:true}" 88 + enable: "${LWM2M_BOOTSTRAP_ENABLED:true}"
96 id: "${LWM2M_SERVER_ID:111}" 89 id: "${LWM2M_SERVER_ID:111}"
97 bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" 90 bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
98 - bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_BS:5691}"  
99 - bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_BS:5693}"  
100 - bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_BS:5695}" 91 + bind_port_no_sec: "${LWM2M_BIND_PORT_NO_SEC_BS:5687}"
101 secure: 92 secure:
102 - bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"  
103 - start_psk: "${START_SERVER_PSK_BS:true}"  
104 - start_rpk: "${START_SERVER_RPK_BS:true}"  
105 - start_x509: "${START_SERVER_X509_BS:true}"  
106 - bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK_BS:5692}"  
107 - bind_port_rpk: "${LWM2M_BIND_PORT_SER_RPK_BS:5694}"  
108 - bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509_BS:5696}"  
109 - # Only RPK: Public & Private Key 93 + bind_address_security: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
  94 + bind_port_security: "${LWM2M_BIND_PORT_SEC_BS:5688}"
  95 + # Only for RPK: Public & Private Key. If the keystore file is missing or not working
110 public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}" 96 public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}"
111 public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}" 97 public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}"
112 private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}" 98 private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}"
113 # Only Certificate_x509: 99 # Only Certificate_x509:
114 alias: "${LWM2M_KEYSTORE_ALIAS_BOOTSTRAP:bootstrap}" 100 alias: "${LWM2M_KEYSTORE_ALIAS_BOOTSTRAP:bootstrap}"
115 - # Redis 101 + # Redis
116 redis_url: "${LWM2M_REDIS_URL:''}" 102 redis_url: "${LWM2M_REDIS_URL:''}"
  103 +
117 sessions: 104 sessions:
118 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" 105 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
119 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" 106 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
@@ -27,7 +27,7 @@ export const DEFAULT_ID_SERVER = 123; @@ -27,7 +27,7 @@ export const DEFAULT_ID_SERVER = 123;
27 export const DEFAULT_ID_BOOTSTRAP = 111; 27 export const DEFAULT_ID_BOOTSTRAP = 111;
28 export const DEFAULT_HOST_NAME = 'localhost'; 28 export const DEFAULT_HOST_NAME = 'localhost';
29 export const DEFAULT_PORT_SERVER_NO_SEC = 5685; 29 export const DEFAULT_PORT_SERVER_NO_SEC = 5685;
30 -export const DEFAULT_PORT_BOOTSTRAP_NO_SEC = 5691; 30 +export const DEFAULT_PORT_BOOTSTRAP_NO_SEC = 5686;
31 export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1; 31 export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1;
32 export const DEFAULT_LIFE_TIME = 300; 32 export const DEFAULT_LIFE_TIME = 300;
33 export const DEFAULT_MIN_PERIOD = 1; 33 export const DEFAULT_MIN_PERIOD = 1;