From 8128c4282425d12d8ad9a14ffd8996d105fc160c Mon Sep 17 00:00:00 2001 From: Vineet Garg Date: Sat, 20 Jun 2015 20:54:39 +0530 Subject: [PATCH] Added support to send payload over ssl --- src/org/kde/kdeconnect/Backends/BaseLink.java | 8 ++- .../Backends/LanBackend/LanLink.java | 60 ++++++++++++++++--- .../Backends/LanBackend/LanLinkProvider.java | 5 +- .../LoopbackBackend/LoopbackLink.java | 6 +- .../LoopbackBackend/LoopbackLinkProvider.java | 2 +- .../Helpers/SecurityHelpers/SslHelper.java | 26 +++++--- 6 files changed, 85 insertions(+), 22 deletions(-) diff --git a/src/org/kde/kdeconnect/Backends/BaseLink.java b/src/org/kde/kdeconnect/Backends/BaseLink.java index 579a7af4..e68ee8b7 100644 --- a/src/org/kde/kdeconnect/Backends/BaseLink.java +++ b/src/org/kde/kdeconnect/Backends/BaseLink.java @@ -20,6 +20,8 @@ package org.kde.kdeconnect.Backends; +import android.content.Context; + import org.kde.kdeconnect.Device; import org.kde.kdeconnect.NetworkPackage; @@ -30,12 +32,14 @@ import java.util.ArrayList; public abstract class BaseLink { + protected final Context context; private final BaseLinkProvider linkProvider; - private final String deviceId; + protected final String deviceId; private final ArrayList receivers = new ArrayList(); protected PrivateKey privateKey; - protected BaseLink(String deviceId, BaseLinkProvider linkProvider) { + protected BaseLink(Context context,String deviceId, BaseLinkProvider linkProvider) { + this.context = context; this.linkProvider = linkProvider; this.deviceId = deviceId; } diff --git a/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java b/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java index 126bcc6c..d1e41c7c 100644 --- a/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java +++ b/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java @@ -20,6 +20,7 @@ package org.kde.kdeconnect.Backends.LanBackend; +import android.content.Context; import android.util.Log; import org.json.JSONObject; @@ -27,6 +28,7 @@ import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Backends.BaseLinkProvider; import org.kde.kdeconnect.Device; import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper; +import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper; import org.kde.kdeconnect.NetworkPackage; import java.io.IOException; @@ -37,9 +39,9 @@ import java.net.ServerSocket; import java.net.Socket; import java.nio.channels.NotYetConnectedException; import java.security.PublicKey; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.TimeoutException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocketFactory; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -61,8 +63,8 @@ public class LanLink extends BaseLink { this.onSsl = value; } - public LanLink(Channel channel, String deviceId, BaseLinkProvider linkProvider) { - super(deviceId, linkProvider); + public LanLink(Context context,Channel channel, String deviceId, BaseLinkProvider linkProvider) { + super(context,deviceId, linkProvider); this.channel = channel; } @@ -79,7 +81,7 @@ public class LanLink extends BaseLink { //Prepare socket for the payload final ServerSocket server; if (np.hasPayload()) { - server = openTcpSocketOnFreePort(); + server = openTcpSocketOnFreePort(context, deviceId, onSsl); JSONObject payloadTransferInfo = new JSONObject(); payloadTransferInfo.put("port", server.getLocalPort()); np.setPayloadTransferInfo(payloadTransferInfo); @@ -182,11 +184,19 @@ public class LanLink extends BaseLink { Socket socket = null; try { - socket = new Socket(); + // Use ssl if existing link is on ssl + if (onSsl) { + SSLContext sslContext = SslHelper.getSslContext(context, deviceId, true); + socket = sslContext.getSocketFactory().createSocket(); + } else { + socket = new Socket(); + } + int tcpPort = np.getPayloadTransferInfo().getInt("port"); InetSocketAddress address = (InetSocketAddress)channel.remoteAddress(); socket.connect(new InetSocketAddress(address.getAddress(), tcpPort)); np.setPayload(socket.getInputStream(), np.getPayloadSize()); + Log.e("KDE/LanLink", "Has payload "); } catch (Exception e) { try { socket.close(); } catch(Exception ignored) { } e.printStackTrace(); @@ -198,8 +208,16 @@ public class LanLink extends BaseLink { packageReceived(np); } + static ServerSocket openTcpSocketOnFreePort(Context context, String deviceId, boolean onSsl) throws IOException { + if (onSsl) { + return openSecureServerSocket(context, deviceId); + } else { + return openUnsecureSocketOnFreePort(); + } + } - static ServerSocket openTcpSocketOnFreePort() throws IOException { + + static ServerSocket openUnsecureSocketOnFreePort() throws IOException { boolean success = false; int tcpPort = 1739; ServerSocket candidateServer = null; @@ -221,4 +239,30 @@ public class LanLink extends BaseLink { return candidateServer; } + static ServerSocket openSecureServerSocket(Context context, String deviceId) throws IOException{ + boolean success = false; + int tcpPort = 1739; + + SSLContext tlsContext = SslHelper.getSslContext(context, deviceId, true); + SSLServerSocketFactory sslServerSocketFactory = tlsContext.getServerSocketFactory(); + + ServerSocket candidateServer = null; + while(!success) { + try { + candidateServer = sslServerSocketFactory.createServerSocket(); + candidateServer.bind(new InetSocketAddress(tcpPort)); + success = true; + Log.i("LanLink", "Using port "+tcpPort); + } catch(IOException e) { + //Log.e("LanLink", "Exception opening serversocket: "+e); + tcpPort++; + if (tcpPort >= 1764) { + Log.e("LanLink", "No more ports available"); + throw e; + } + } + } + return candidateServer; + } + } diff --git a/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java b/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java index b9754d46..8a512b96 100644 --- a/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java +++ b/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java @@ -149,6 +149,7 @@ public class LanLinkProvider extends BaseLinkProvider { } final NetworkPackage np = NetworkPackage.unserialize(theMessage); + Log.e("KDE/LanLinkProvider", theMessage); if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_IDENTITY)) { @@ -159,7 +160,7 @@ public class LanLinkProvider extends BaseLinkProvider { //Log.i("KDE/LanLinkProvider", "Identity package received from " + np.getString("deviceName")); - final LanLink link = new LanLink(ctx.channel(), np.getString("deviceId"), LanLinkProvider.this); + final LanLink link = new LanLink(context, ctx.channel(), np.getString("deviceId"), LanLinkProvider.this); nioLinks.put(ctx.channel().hashCode(), link); //Log.i("KDE/LanLinkProvider","nioLinks.size(): " + nioLinks.size()); @@ -258,7 +259,7 @@ public class LanLinkProvider extends BaseLinkProvider { Log.e("KDE/LanLinkProvider", "Remote device supports ssl, ssl handler added"); } - final LanLink link = new LanLink(channel, identityPackage.getString("deviceId"), LanLinkProvider.this); + final LanLink link = new LanLink(context, channel, identityPackage.getString("deviceId"), LanLinkProvider.this); new Thread(new Runnable() { @Override public void run() { diff --git a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java index 79949e72..e63815d8 100644 --- a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java +++ b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java @@ -20,6 +20,8 @@ package org.kde.kdeconnect.Backends.LoopbackBackend; +import android.content.Context; + import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Backends.BaseLinkProvider; import org.kde.kdeconnect.Device; @@ -30,8 +32,8 @@ import java.security.PublicKey; public class LoopbackLink extends BaseLink { - public LoopbackLink(BaseLinkProvider linkProvider) { - super("loopback", linkProvider); + public LoopbackLink(Context context, BaseLinkProvider linkProvider) { + super(context, "loopback", linkProvider); } @Override diff --git a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java index bd9c41b4..c25ae39d 100644 --- a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java +++ b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java @@ -45,7 +45,7 @@ public class LoopbackLinkProvider extends BaseLinkProvider { @Override public void onNetworkChange() { NetworkPackage np = NetworkPackage.createIdentityPackage(context); - connectionAccepted(np, new LoopbackLink(this)); + connectionAccepted(np, new LoopbackLink(context, this)); } /* @Override diff --git a/src/org/kde/kdeconnect/Helpers/SecurityHelpers/SslHelper.java b/src/org/kde/kdeconnect/Helpers/SecurityHelpers/SslHelper.java index 3636904d..af39ef00 100644 --- a/src/org/kde/kdeconnect/Helpers/SecurityHelpers/SslHelper.java +++ b/src/org/kde/kdeconnect/Helpers/SecurityHelpers/SslHelper.java @@ -45,6 +45,7 @@ import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.Date; +import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; @@ -121,13 +122,8 @@ public class SslHelper { } } - public static SSLEngine getSslEngine(final Context context, final String deviceId, SslMode sslMode) { - - try{ - // Check whether device is trusted or not - SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE); - final boolean isDeviceTrusted = preferences.getBoolean(deviceId, false); - + public static SSLContext getSslContext(Context context, String deviceId, boolean isDeviceTrusted) { + try { // Get device private key PrivateKey privateKey = RsaHelper.getPrivateKey(context); @@ -181,7 +177,23 @@ public class SslHelper { }else { tlsContext.init(keyManagerFactory.getKeyManagers(), trustAllCerts, new SecureRandom()); } + return tlsContext; + } catch (Exception e) { + Log.e("KDE/SslHelper", "Error creating tls context"); + e.printStackTrace(); + } + return null; + } + + public static SSLEngine getSslEngine(final Context context, final String deviceId, SslMode sslMode) { + + try{ + + SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE); + final boolean isDeviceTrusted = preferences.getBoolean(deviceId, false); + + SSLContext tlsContext = getSslContext(context, deviceId, isDeviceTrusted); SSLEngine sslEngine = tlsContext.createSSLEngine(); if (sslMode == SslMode.Client){