diff --git a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/AstartePairingHandler.java b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/AstartePairingHandler.java index 18ff86f..bc60bd7 100644 --- a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/AstartePairingHandler.java +++ b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/AstartePairingHandler.java @@ -17,12 +17,15 @@ public class AstartePairingHandler { private Certificate m_certificate; + private boolean ignoreSSLErrors; + public AstartePairingHandler( String pairingUrl, String astarteRealm, String deviceId, String credentialSecret, - AstarteCryptoStore cryptoStore) { + AstarteCryptoStore cryptoStore, + boolean ignoreSSLErrors) { m_astarteRealm = astarteRealm; m_deviceId = deviceId; m_credentialSecret = credentialSecret; @@ -31,6 +34,8 @@ public AstartePairingHandler( m_AstartePairingService = new AstartePairingService(pairingUrl, astarteRealm); m_certificate = m_cryptoStore.getCertificate(); + + this.ignoreSSLErrors = ignoreSSLErrors; } public void init() throws AstartePairingException { @@ -74,7 +79,8 @@ public boolean isCertificateAvailable() { private void reloadTransports() throws AstartePairingException { m_transports = - m_AstartePairingService.reloadTransports(m_credentialSecret, m_cryptoStore, m_deviceId); + m_AstartePairingService.reloadTransports( + m_credentialSecret, m_cryptoStore, m_deviceId, ignoreSSLErrors); } public void requestNewCertificate() throws AstartePairingException { diff --git a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/AstartePairingService.java b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/AstartePairingService.java index 4df3ad4..1269d30 100644 --- a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/AstartePairingService.java +++ b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/AstartePairingService.java @@ -105,7 +105,10 @@ public String registerDevice(String jwtToken, String deviceId) } protected List reloadTransports( - String credentialSecret, AstarteCryptoStore cryptoStore, String deviceId) + String credentialSecret, + AstarteCryptoStore cryptoStore, + String deviceId, + boolean ignoreSSLErrors) throws AstartePairingException { // Build the request URL for Astarte MQTT v1 HttpUrl requestUrl; @@ -161,7 +164,8 @@ protected List reloadTransports( m_astarteRealm, deviceId, transportObjects.getJSONObject(key), - cryptoStore); + cryptoStore, + ignoreSSLErrors); transports.add(supportedTransport); } catch (Exception e) { e.printStackTrace(); diff --git a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/crypto/AstarteCryptoStore.java b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/crypto/AstarteCryptoStore.java index 1e93ab4..66fcf93 100644 --- a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/crypto/AstarteCryptoStore.java +++ b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/crypto/AstarteCryptoStore.java @@ -21,7 +21,7 @@ public interface AstarteCryptoStore { String generateCSR(String directoryString) throws IOException, OperatorCreationException; - SSLSocketFactory getSSLSocketFactory() + SSLSocketFactory getSSLSocketFactory(boolean ignoreSSLErrors) throws KeyManagementException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException; } diff --git a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/transport/AstarteTransportFactory.java b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/transport/AstarteTransportFactory.java index fead04a..4284a0a 100644 --- a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/transport/AstarteTransportFactory.java +++ b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/transport/AstarteTransportFactory.java @@ -1,5 +1,6 @@ package org.astarteplatform.devicesdk.transport; +import javax.net.ssl.*; import org.astarteplatform.devicesdk.crypto.AstarteCryptoStore; import org.astarteplatform.devicesdk.protocol.AstarteProtocolType; import org.astarteplatform.devicesdk.transport.mqtt.AstarteMqttV1Transport; @@ -12,7 +13,8 @@ public static AstarteTransport createAstarteTransportFromPairing( String astarteRealm, String deviceId, JSONObject protocolData, - AstarteCryptoStore cryptoStore) { + AstarteCryptoStore cryptoStore, + boolean ignoreSSLErrors) { switch (protocolType) { case ASTARTE_MQTT_V1: try { @@ -22,7 +24,11 @@ public static AstarteTransport createAstarteTransportFromPairing( } return new AstarteMqttV1Transport( new MutualSSLAuthenticationMqttConnectionInfo( - brokerUrl, astarteRealm, deviceId, cryptoStore.getSSLSocketFactory())); + brokerUrl, + astarteRealm, + deviceId, + cryptoStore.getSSLSocketFactory(ignoreSSLErrors), + ignoreSSLErrors)); } catch (Exception e) { e.printStackTrace(); return null; diff --git a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/transport/mqtt/MutualSSLAuthenticationMqttConnectionInfo.java b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/transport/mqtt/MutualSSLAuthenticationMqttConnectionInfo.java index cf82515..7c33d6a 100644 --- a/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/transport/mqtt/MutualSSLAuthenticationMqttConnectionInfo.java +++ b/DeviceSDK/src/main/java/org/astarteplatform/devicesdk/transport/mqtt/MutualSSLAuthenticationMqttConnectionInfo.java @@ -9,7 +9,11 @@ public class MutualSSLAuthenticationMqttConnectionInfo implements MqttConnection private final String m_clientId; public MutualSSLAuthenticationMqttConnectionInfo( - String brokerUrl, String astarteRealm, String deviceId, SSLSocketFactory sslSocketFactory) { + String brokerUrl, + String astarteRealm, + String deviceId, + SSLSocketFactory sslSocketFactory, + boolean ignoreSSLErrors) { m_brokerUrl = brokerUrl; m_mqttConnectOptions = new MqttConnectOptions(); m_mqttConnectOptions.setConnectionTimeout(60); @@ -24,6 +28,9 @@ public MutualSSLAuthenticationMqttConnectionInfo( } catch (Exception e) { e.printStackTrace(); } + if (ignoreSSLErrors) { + m_mqttConnectOptions.setHttpsHostnameVerificationEnabled(false); + } m_clientId = astarteRealm + "/" + deviceId; } diff --git a/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidCryptoStore.java b/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidCryptoStore.java index 25bb272..9339dd8 100644 --- a/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidCryptoStore.java +++ b/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidCryptoStore.java @@ -139,10 +139,10 @@ public String generateCSR(String directoryString) throws IOException, OperatorCr } @Override - public SSLSocketFactory getSSLSocketFactory() + public SSLSocketFactory getSSLSocketFactory(boolean ignoreSSLErrors) throws KeyManagementException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException { - return new AstarteAndroidMutualSSLSocketFactory(); + return new AstarteAndroidMutualSSLSocketFactory(ignoreSSLErrors); } private String csrToString(PKCS10CertificationRequest csr) throws IOException { diff --git a/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidDevice.java b/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidDevice.java index e794f5c..7a7c2e2 100644 --- a/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidDevice.java +++ b/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidDevice.java @@ -16,13 +16,33 @@ public AstarteAndroidDevice( String pairingBaseUrl, Context context) throws JSONException, AstarteInvalidInterfaceException { + this( + deviceId, + astarteRealm, + credentialSecret, + interfaceProvider, + pairingBaseUrl, + context, + false); + } + + public AstarteAndroidDevice( + String deviceId, + String astarteRealm, + String credentialSecret, + AstarteInterfaceProvider interfaceProvider, + String pairingBaseUrl, + Context context, + boolean ignoreSSLErrors) + throws JSONException, AstarteInvalidInterfaceException { super( new AstartePairingHandler( pairingBaseUrl, astarteRealm, deviceId, credentialSecret, - new AstarteAndroidCryptoStore()), + new AstarteAndroidCryptoStore(), + ignoreSSLErrors), new AstarteAndroidPropertyStorage(context, "astarte.property_store." + deviceId), new AstarteAndroidFailedMessageStorage( AstarteAndroidRoomDatabase.getDatabase(context).astarteFailedMessageDao()), diff --git a/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidMutualSSLSocketFactory.java b/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidMutualSSLSocketFactory.java index d144496..1b394d5 100644 --- a/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidMutualSSLSocketFactory.java +++ b/DeviceSDKAndroid/src/main/java/org/astarteplatform/devicesdk/android/AstarteAndroidMutualSSLSocketFactory.java @@ -11,25 +11,43 @@ import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509ExtendedKeyManager; +import javax.net.ssl.*; class AstarteAndroidMutualSSLSocketFactory extends SSLSocketFactory { private SSLSocketFactory internalSSLSocketFactory; - public AstarteAndroidMutualSSLSocketFactory() + public AstarteAndroidMutualSSLSocketFactory(boolean ignoreSSLErrors) throws KeyManagementException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException { - // CA certificate is used to authenticate server - TrustManagerFactory trustManagerFactory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - KeyStore caStore = KeyStore.getInstance("AndroidCAStore"); - caStore.load(null); - trustManagerFactory.init(caStore); + TrustManager[] trustManagers; + if (ignoreSSLErrors) { + TrustManager[] trustAllCerts = + new TrustManager[] { + new X509TrustManager() { + @Override + public void checkClientTrusted( + java.security.cert.X509Certificate[] chain, String authType) {} + + @Override + public void checkServerTrusted( + java.security.cert.X509Certificate[] chain, String authType) {} + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[] {}; + } + } + }; + trustManagers = trustAllCerts; + } else { + // CA certificate is used to authenticate server + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + KeyStore caStore = KeyStore.getInstance("AndroidCAStore"); + caStore.load(null); + trustManagerFactory.init(caStore); + trustManagers = trustManagerFactory.getTrustManagers(); + } // client key and certificates are sent to server so it can authenticate us final KeyStore androidKeyStore = KeyStore.getInstance("AndroidKeyStore"); @@ -84,7 +102,7 @@ public PrivateKey getPrivateKey(String alias) { // finally, create SSL socket factory SSLContext context = SSLContext.getInstance("TLSv1.2"); - context.init(new KeyManager[] {keyManager}, trustManagerFactory.getTrustManagers(), null); + context.init(new KeyManager[] {keyManager}, trustManagers, null); internalSSLSocketFactory = context.getSocketFactory(); } diff --git a/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericCryptoStore.java b/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericCryptoStore.java index ed3bd06..231c9db 100644 --- a/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericCryptoStore.java +++ b/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericCryptoStore.java @@ -98,11 +98,11 @@ public String generateCSR(String directoryString) throws IOException, OperatorCr } @Override - public SSLSocketFactory getSSLSocketFactory() + public SSLSocketFactory getSSLSocketFactory(boolean ignoreSSLErrors) throws KeyManagementException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException { if (m_socketFactory == null) { - m_socketFactory = new AstarteGenericMutualSSLSocketFactory(this); + m_socketFactory = new AstarteGenericMutualSSLSocketFactory(this, ignoreSSLErrors); } return m_socketFactory; diff --git a/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericDevice.java b/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericDevice.java index d0d8061..7187ad6 100644 --- a/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericDevice.java +++ b/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericDevice.java @@ -22,6 +22,26 @@ public AstarteGenericDevice( ConnectionSource connectionSource) throws JSONException, AstarteInvalidInterfaceException, AstartePropertyStorageException, SQLException { + this( + deviceId, + astarteRealm, + credentialSecret, + interfaceProvider, + pairingBaseUrl, + connectionSource, + false); + } + + public AstarteGenericDevice( + String deviceId, + String astarteRealm, + String credentialSecret, + AstarteInterfaceProvider interfaceProvider, + String pairingBaseUrl, + ConnectionSource connectionSource, + boolean ignoreSSLErrors) + throws JSONException, AstarteInvalidInterfaceException, AstartePropertyStorageException, + SQLException { this( deviceId, astarteRealm, @@ -31,7 +51,8 @@ public AstarteGenericDevice( new AstarteGenericPropertyStorage( DaoManager.createDao(connectionSource, AstarteGenericPropertyEntry.class)), new AstarteGenericFailedMessageStorage( - DaoManager.createDao(connectionSource, AstarteGenericFailedMessage.class))); + DaoManager.createDao(connectionSource, AstarteGenericFailedMessage.class)), + ignoreSSLErrors); } public AstarteGenericDevice( @@ -41,7 +62,8 @@ public AstarteGenericDevice( AstarteInterfaceProvider interfaceProvider, String pairingBaseUrl, AstartePropertyStorage propertyStorage, - AstarteFailedMessageStorage failedMessageStorage) + AstarteFailedMessageStorage failedMessageStorage, + boolean ignoreSSLErrors) throws JSONException, AstarteInvalidInterfaceException { super( new AstartePairingHandler( @@ -49,7 +71,8 @@ public AstarteGenericDevice( astarteRealm, deviceId, credentialSecret, - new AstarteGenericCryptoStore()), + new AstarteGenericCryptoStore(), + ignoreSSLErrors), propertyStorage, failedMessageStorage, interfaceProvider); diff --git a/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericMutualSSLSocketFactory.java b/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericMutualSSLSocketFactory.java index fd32440..e144d69 100644 --- a/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericMutualSSLSocketFactory.java +++ b/DeviceSDKGeneric/src/main/java/org/astarteplatform/devicesdk/generic/AstarteGenericMutualSSLSocketFactory.java @@ -15,29 +15,49 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509ExtendedKeyManager; +import javax.net.ssl.*; class AstarteGenericMutualSSLSocketFactory extends SSLSocketFactory { private SSLSocketFactory internalSSLSocketFactory; private AstarteGenericCryptoStore mCryptoStore; - public AstarteGenericMutualSSLSocketFactory(AstarteGenericCryptoStore cryptoStore) + public AstarteGenericMutualSSLSocketFactory( + AstarteGenericCryptoStore cryptoStore, boolean ignoreSSLErrors) throws KeyManagementException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException { - // CA certificate is used to authenticate server - String caFile = System.getProperty("java.home") + "/lib/security/cacerts"; - KeyStore caStore = KeyStore.getInstance(KeyStore.getDefaultType()); - try (InputStream is = Files.newInputStream(Paths.get(caFile))) { - caStore.load(is, null); + TrustManager[] trustManagers; + if (ignoreSSLErrors) { + TrustManager[] trustAllCerts = + new TrustManager[] { + new X509TrustManager() { + @Override + public void checkClientTrusted( + java.security.cert.X509Certificate[] chain, String authType) {} + + @Override + public void checkServerTrusted( + java.security.cert.X509Certificate[] chain, String authType) {} + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[] {}; + } + } + }; + trustManagers = trustAllCerts; + } else { + // CA certificate is used to authenticate server + String caFile = System.getProperty("java.home") + "/lib/security/cacerts"; + KeyStore caStore = KeyStore.getInstance(KeyStore.getDefaultType()); + try (InputStream is = Files.newInputStream(Paths.get(caFile))) { + caStore.load(is, null); + } + + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(caStore); + trustManagers = trustManagerFactory.getTrustManagers(); } - TrustManagerFactory trustManagerFactory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(caStore); mCryptoStore = cryptoStore; @@ -82,7 +102,7 @@ public PrivateKey getPrivateKey(String alias) { // finally, create SSL socket factory SSLContext context = SSLContext.getInstance("TLSv1.2"); - context.init(new KeyManager[] {keyManager}, trustManagerFactory.getTrustManagers(), null); + context.init(new KeyManager[] {keyManager}, trustManagers, null); internalSSLSocketFactory = context.getSocketFactory(); }