diff --git a/src/org/kde/kdeconnect/Backends/BaseLinkProvider.java b/src/org/kde/kdeconnect/Backends/BaseLinkProvider.java index 5876cc02..70231620 100644 --- a/src/org/kde/kdeconnect/Backends/BaseLinkProvider.java +++ b/src/org/kde/kdeconnect/Backends/BaseLinkProvider.java @@ -6,8 +6,11 @@ package org.kde.kdeconnect.Backends; +import androidx.annotation.NonNull; + import org.kde.kdeconnect.NetworkPacket; +import java.security.cert.Certificate; import java.util.concurrent.CopyOnWriteArrayList; public abstract class BaseLinkProvider { @@ -15,7 +18,10 @@ public abstract class BaseLinkProvider { private final CopyOnWriteArrayList connectionReceivers = new CopyOnWriteArrayList<>(); public interface ConnectionReceiver { - void onConnectionReceived(NetworkPacket identityPacket, BaseLink link); + void onConnectionReceived(@NonNull final String deviceId, + @NonNull final Certificate certificate, + @NonNull final NetworkPacket identityPacket, + @NonNull final BaseLink link); void onConnectionLost(BaseLink link); } @@ -28,10 +34,13 @@ public abstract class BaseLinkProvider { } //These two should be called when the provider links to a new computer - protected void connectionAccepted(NetworkPacket identityPacket, BaseLink link) { + protected void connectionAccepted(@NonNull final String deviceId, + @NonNull final Certificate certificate, + @NonNull final NetworkPacket identityPacket, + @NonNull final BaseLink link) { //Log.i("KDE/LinkProvider", "connectionAccepted"); for(ConnectionReceiver cr : connectionReceivers) { - cr.onConnectionReceived(identityPacket, link); + cr.onConnectionReceived(deviceId, certificate, identityPacket, link); } } protected void connectionLost(BaseLink link) { @@ -45,8 +54,6 @@ public abstract class BaseLinkProvider { public abstract void onStart(); public abstract void onStop(); public abstract void onNetworkChange(); - - //public abstract int getPriority(); public abstract String getName(); } diff --git a/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLinkProvider.java b/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLinkProvider.java index a182b8b7..9cab8a80 100644 --- a/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLinkProvider.java +++ b/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLinkProvider.java @@ -15,10 +15,12 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Parcelable; +import android.util.Base64; import android.util.Log; import org.kde.kdeconnect.Backends.BaseLinkProvider; import org.kde.kdeconnect.Device; +import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper; import org.kde.kdeconnect.Helpers.ThreadHelper; import org.kde.kdeconnect.NetworkPacket; @@ -27,6 +29,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -48,8 +52,12 @@ public class BluetoothLinkProvider extends BaseLinkProvider { private ServerRunnable serverRunnable; private ClientRunnable clientRunnable; - private void addLink(NetworkPacket identityPacket, BluetoothLink link) { + private void addLink(NetworkPacket identityPacket, BluetoothLink link) throws CertificateException { String deviceId = identityPacket.getString("deviceId"); + String certificateString = identityPacket.getString("certificate"); + byte[] certificateBytes = Base64.decode(certificateString, 0); + Certificate certificate = SslHelper.parseCertificate(certificateBytes); + Log.i("BluetoothLinkProvider", "addLink to " + deviceId); BluetoothLink oldLink = visibleComputers.get(deviceId); if (oldLink == link) { @@ -57,7 +65,7 @@ public class BluetoothLinkProvider extends BaseLinkProvider { return; } visibleComputers.put(deviceId, link); - connectionAccepted(identityPacket, link); + connectionAccepted(deviceId, certificate, identityPacket, link); link.startListening(); if (oldLink != null) { Log.i("BluetoothLinkProvider", "Removing old connection to same device"); @@ -189,6 +197,7 @@ public class BluetoothLinkProvider extends BaseLinkProvider { InputStream inputStream = connection.getDefaultInputStream(); NetworkPacket np = NetworkPacket.createIdentityPacket(context); + np.set("certificate", Base64.encodeToString(SslHelper.certificate.getEncoded(), 0)); byte[] message = np.serialize().getBytes(Charsets.UTF_8); outputStream.write(message); outputStream.flush(); @@ -371,7 +380,11 @@ public class BluetoothLinkProvider extends BaseLinkProvider { link.sendPacket(np2, new Device.SendPacketStatusCallback() { @Override public void onSuccess() { - addLink(identityPacket, link); + try { + addLink(identityPacket, link); + } catch (CertificateException e) { + e.printStackTrace(); + } } @Override diff --git a/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java b/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java index 23f67f6b..746af2e0 100644 --- a/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java +++ b/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java @@ -211,9 +211,8 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis String mode = clientMode ? "client" : "server"; try { Certificate certificate = event.getPeerCertificates()[0]; - identityPacket.set("certificate", Base64.encodeToString(certificate.getEncoded(), 0)); Log.i("KDE/LanLinkProvider", "Handshake as " + mode + " successful with " + identityPacket.getString("deviceName") + " secured with " + event.getCipherSuite()); - addLink(identityPacket, sslsocket); + addLink(deviceId, certificate, identityPacket, sslsocket); } catch (Exception e) { Log.e("KDE/LanLinkProvider", "Handshake as " + mode + " failed with " + identityPacket.getString("deviceName"), e); Device device = KdeConnect.getInstance().getDevice(deviceId); @@ -252,14 +251,13 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis * {@link Device#addLink(NetworkPacket, BaseLink)} crashes on some devices running Oreo 8.1 (SDK level 27). *

* - * @param identityPacket representation of remote device - * @param socket a new Socket, which should be used to receive packets from the remote device - * @param connectionOrigin which side started this connection + * @param deviceId remote device id + * @param certificate remote device certificate + * @param identityPacket identity packet with the remote device's device name, type, protocol version, etc. + * @param socket a new Socket, which should be used to send and receive packets from the remote device * @throws IOException if an exception is thrown by {@link LanLink#reset(SSLSocket, LanLink.ConnectionStarted)} */ - private void addLink(final NetworkPacket identityPacket, SSLSocket socket) throws IOException { - - String deviceId = identityPacket.getString("deviceId"); + private void addLink(String deviceId, Certificate certificate, final NetworkPacket identityPacket, SSLSocket socket) throws IOException { LanLink currentLink = visibleComputers.get(deviceId); if (currentLink != null) { //Update old link @@ -271,7 +269,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis //Let's create the link LanLink link = new LanLink(context, deviceId, this, socket); visibleComputers.put(deviceId, link); - connectionAccepted(identityPacket, link); + connectionAccepted(deviceId, certificate, identityPacket, link); } } diff --git a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java index 01006b61..14fc9b5c 100644 --- a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java +++ b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java @@ -9,6 +9,8 @@ package org.kde.kdeconnect.Backends.LoopbackBackend; import android.content.Context; import org.kde.kdeconnect.Backends.BaseLinkProvider; +import org.kde.kdeconnect.Helpers.DeviceHelper; +import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper; import org.kde.kdeconnect.NetworkPacket; public class LoopbackLinkProvider extends BaseLinkProvider { @@ -31,14 +33,10 @@ public class LoopbackLinkProvider extends BaseLinkProvider { @Override public void onNetworkChange() { NetworkPacket np = NetworkPacket.createIdentityPacket(context); - connectionAccepted(np, new LoopbackLink(context, this)); + String deviceId = DeviceHelper.getDeviceId(context); + connectionAccepted(deviceId, SslHelper.certificate, np, new LoopbackLink(context, this)); } -/* - @Override - public int getPriority() { - return 0; - } -*/ + @Override public String getName() { return "LoopbackLinkProvider"; diff --git a/src/org/kde/kdeconnect/Device.java b/src/org/kde/kdeconnect/Device.java index a2e98f3d..7bc8ce9c 100644 --- a/src/org/kde/kdeconnect/Device.java +++ b/src/org/kde/kdeconnect/Device.java @@ -40,6 +40,7 @@ import org.kde.kdeconnect_tp.R; import java.io.IOException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -130,18 +131,20 @@ public class Device implements BaseLink.PacketReceiver { } } - //Remembered trusted device, we need to wait for a incoming devicelink to communicate - Device(Context context, String deviceId) { - settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE); - - //Log.e("Device","Constructor A"); + // Remembered trusted device, we need to wait for a incoming Link to communicate + Device(@NonNull Context context, @NonNull String deviceId) throws CertificateException { + Log.i("Device","Loading trusted device"); this.context = context; + + this.settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE); + this.pairingHandler = new PairingHandler(this, pairingCallback, PairingHandler.PairState.Paired); + this.deviceId = deviceId; this.name = settings.getString("deviceName", context.getString(R.string.unknown_device)); - this.pairingHandler = new PairingHandler(this, pairingCallback, PairingHandler.PairState.Paired); - this.protocolVersion = DeviceHelper.ProtocolVersion; //We don't know it yet + this.protocolVersion = 0; //We don't know it yet this.deviceType = DeviceType.FromString(settings.getString("deviceType", "desktop")); + this.certificate = SslHelper.getDeviceCertificate(context, deviceId); //Assume every plugin is supported until addLink is called and we can get the actual list supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins()); @@ -150,21 +153,24 @@ public class Device implements BaseLink.PacketReceiver { //reloadPluginsFromSettings(); } - //Device known via an incoming connection sent to us via a devicelink, we know everything but we don't trust it yet - Device(Context context, NetworkPacket np, BaseLink dl) { - - //Log.e("Device","Constructor B"); + // Device known via an incoming connection sent to us via a Link, we don't trust it yet + Device(@NonNull Context context, @NonNull String deviceId, @NonNull Certificate certificate, @NonNull NetworkPacket identityPacket, @NonNull BaseLink dl) { + Log.i("Device","Creating untrusted device"); this.context = context; - this.deviceId = np.getString("deviceId"); - this.name = context.getString(R.string.unknown_device); //We read it in addLink - this.pairingHandler= new PairingHandler(this, pairingCallback, PairingHandler.PairState.NotPaired); - this.protocolVersion = 0; + + this.settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE); + this.pairingHandler = new PairingHandler(this, pairingCallback, PairingHandler.PairState.NotPaired); + + this.deviceId = deviceId; + this.certificate = certificate; + + // The following properties are read from the identityPacket in addLink since they can change in future identity packets + this.name = context.getString(R.string.unknown_device); this.deviceType = DeviceType.Computer; + this.protocolVersion = 0; - settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE); - - addLink(np, dl); + addLink(identityPacket, dl); } public String getName() { @@ -255,12 +261,8 @@ public class Device implements BaseLink.PacketReceiver { try { String encodedCertificate = Base64.encodeToString(certificate.getEncoded(), 0); editor.putString("certificate", encodedCertificate); - } catch (NullPointerException n) { - Log.w("PairingHandler", "Certificate is null, remote device does not support SSL", n); - return; - } catch (CertificateEncodingException c) { - Log.e("PairingHandler", "Error encoding certificate", c); - return; + } catch(CertificateEncodingException e) { + throw new RuntimeException(e); } editor.putString("deviceName", name); editor.putString("deviceType", deviceType.toString()); @@ -384,19 +386,6 @@ public class Device implements BaseLink.PacketReceiver { this.deviceType = DeviceType.FromString(identityPacket.getString("deviceType", "desktop")); } - if (identityPacket.has("certificate")) { - String certificateString = identityPacket.getString("certificate"); - - try { - byte[] certificateBytes = Base64.decode(certificateString, 0); - certificate = SslHelper.parseCertificate(certificateBytes); - Log.i("KDE/Device", "Got certificate "); - } catch (Exception e) { - Log.e("KDE/Device", "Error getting certificate", e); - - } - } - Log.i("KDE/Device", "addLink " + link.getLinkProvider().getName() + " -> " + getName() + " active links: " + links.size()); Set outgoingCapabilities = identityPacket.getStringSet("outgoingCapabilities", null); diff --git a/src/org/kde/kdeconnect/Helpers/SecurityHelpers/SslHelper.java b/src/org/kde/kdeconnect/Helpers/SecurityHelpers/SslHelper.java index 03385924..be903231 100644 --- a/src/org/kde/kdeconnect/Helpers/SecurityHelpers/SslHelper.java +++ b/src/org/kde/kdeconnect/Helpers/SecurityHelpers/SslHelper.java @@ -176,26 +176,29 @@ public class SslHelper { return !cert.isEmpty(); } - private static SSLContext getSslContext(Context context, String deviceId, boolean isDeviceTrusted) { + /** + * Returns the stored certificate for a trusted device + **/ + public static Certificate getDeviceCertificate(Context context, String deviceId) throws CertificateException { + SharedPreferences devicePreferences = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE); + byte[] certificateBytes = Base64.decode(devicePreferences.getString("certificate", ""), 0); + return parseCertificate(certificateBytes); + } + + private static SSLContext getSslContextForDevice(Context context, String deviceId, boolean isDeviceTrusted) { //TODO: Cache try { // Get device private key PrivateKey privateKey = RsaHelper.getPrivateKey(context); - // Get remote device certificate if trusted - Certificate remoteDeviceCertificate = null; - if (isDeviceTrusted) { - SharedPreferences devicePreferences = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE); - byte[] certificateBytes = Base64.decode(devicePreferences.getString("certificate", ""), 0); - remoteDeviceCertificate = parseCertificate(certificateBytes); - } - // Setup keystore KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, null); keyStore.setKeyEntry("key", privateKey, "".toCharArray(), new Certificate[]{certificate}); - // Set certificate if device trusted - if (remoteDeviceCertificate != null) { + + // Add device certificate if device trusted + if (isDeviceTrusted) { + Certificate remoteDeviceCertificate = getDeviceCertificate(context, deviceId); keyStore.setCertificateEntry(deviceId, remoteDeviceCertificate); } @@ -239,7 +242,7 @@ public class SslHelper { } public static SSLSocket convertToSslSocket(Context context, Socket socket, String deviceId, boolean isDeviceTrusted, boolean clientMode) throws IOException { - SSLSocketFactory sslsocketFactory = SslHelper.getSslContext(context, deviceId, isDeviceTrusted).getSocketFactory(); + SSLSocketFactory sslsocketFactory = SslHelper.getSslContextForDevice(context, deviceId, isDeviceTrusted).getSocketFactory(); SSLSocket sslsocket = (SSLSocket) sslsocketFactory.createSocket(socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true); SslHelper.configureSslSocket(sslsocket, isDeviceTrusted, clientMode); return sslsocket; diff --git a/src/org/kde/kdeconnect/KdeConnect.java b/src/org/kde/kdeconnect/KdeConnect.java index 747f2197..b4e2138c 100644 --- a/src/org/kde/kdeconnect/KdeConnect.java +++ b/src/org/kde/kdeconnect/KdeConnect.java @@ -5,6 +5,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.util.Log; +import androidx.annotation.NonNull; + import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Backends.BaseLinkProvider; import org.kde.kdeconnect.Helpers.DeviceHelper; @@ -17,6 +19,8 @@ import org.kde.kdeconnect.Plugins.PluginFactory; import org.kde.kdeconnect.UserInterface.PairingHandler; import org.kde.kdeconnect.UserInterface.ThemeUtil; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -105,9 +109,14 @@ public class KdeConnect extends Application { for (String deviceId : trustedDevices) { //Log.e("BackgroundService", "Loading device "+deviceId); if (preferences.getBoolean(deviceId, false)) { - Device device = new Device(this, deviceId); - devices.put(deviceId, device); - device.addPairingCallback(devicePairingCallback); + try { + Device device = new Device(this, deviceId); + devices.put(deviceId, device); + device.addPairingCallback(devicePairingCallback); + } catch (CertificateException e) { + Log.e("KdeConnect", "Could not load trusted device, certificate not valid: " + deviceId); + e.printStackTrace(); + } } } } @@ -136,15 +145,17 @@ public class KdeConnect extends Application { private final BaseLinkProvider.ConnectionReceiver connectionListener = new BaseLinkProvider.ConnectionReceiver() { @Override - public void onConnectionReceived(final NetworkPacket identityPacket, final BaseLink link) { - String deviceId = identityPacket.getString("deviceId"); + public void onConnectionReceived(@NonNull final String deviceId, + @NonNull final Certificate certificate, + @NonNull final NetworkPacket identityPacket, + @NonNull final BaseLink link) { Device device = devices.get(deviceId); if (device != null) { Log.i("KDE/Application", "addLink, known device: " + deviceId); device.addLink(identityPacket, link); } else { Log.i("KDE/Application", "addLink,unknown device: " + deviceId); - device = new Device(KdeConnect.this, identityPacket, link); + device = new Device(KdeConnect.this, deviceId, certificate, identityPacket, link); devices.put(deviceId, device); device.addPairingCallback(devicePairingCallback); } diff --git a/tests/org/kde/kdeconnect/DeviceTest.java b/tests/org/kde/kdeconnect/DeviceTest.java index 5c3a5d3b..c42974ed 100644 --- a/tests/org/kde/kdeconnect/DeviceTest.java +++ b/tests/org/kde/kdeconnect/DeviceTest.java @@ -32,6 +32,7 @@ import org.kde.kdeconnect.Backends.LanBackend.LanLink; import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider; import org.kde.kdeconnect.Helpers.DeviceHelper; import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper; +import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper; import org.kde.kdeconnect.UserInterface.PairingHandler; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; @@ -42,6 +43,9 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; @RunWith(PowerMockRunner.class) @PrepareForTest({Base64.class, Log.class, PreferenceManager.class, ContextCompat.class}) @@ -56,16 +60,22 @@ public class DeviceTest { String deviceId = "testDevice"; String name = "Test Device"; - - KeyPair keyPair; - try { - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); - keyGen.initialize(2048); - keyPair = keyGen.genKeyPair(); - } catch (Exception e) { - Log.e("KDE/initializeRsaKeys", "Exception", e); - return; - } + String encodedCertificate = "MIIDVzCCAj+gAwIBAgIBCjANBgkqhkiG9w0BAQUFADBVMS8wLQYDVQQDDCZfZGExNzlhOTFfZjA2\n" + + "NF80NzhlX2JlOGNfMTkzNWQ3NTQ0ZDU0XzEMMAoGA1UECgwDS0RFMRQwEgYDVQQLDAtLZGUgY29u\n" + + "bmVjdDAeFw0xNTA2MDMxMzE0MzhaFw0yNTA2MDMxMzE0MzhaMFUxLzAtBgNVBAMMJl9kYTE3OWE5\n" + + "MV9mMDY0XzQ3OGVfYmU4Y18xOTM1ZDc1NDRkNTRfMQwwCgYDVQQKDANLREUxFDASBgNVBAsMC0tk\n" + + "ZSBjb25uZWN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzH9GxS1lctpwYdSGAoPH\n" + + "ws+MnVaL0PVDCuzrpxzXc+bChR87xofhQIesLPLZEcmUJ1MlEJ6jx4W+gVhvY2tUN7SoiKKbnq8s\n" + + "WjI5ovs5yML3C1zPbOSJAdK613FcdkK+UGd/9dQk54gIozinC58iyTAChVVpB3pAF38EPxwKkuo2\n" + + "qTzwk24d6PRxz1skkzwEphUQQzGboyHsAlJHN1MzM2/yFGB4l8iUua2d3ETyfy/xFEh/SwtGtXE5\n" + + "KLz4cpb0fxjeYQZVruBKxzE07kgDO3zOhmP3LJ/KSPHWYImd1DWmpY9iDvoXr6+V7FAnRloaEIyg\n" + + "7WwdlSCpo3TXVuIjLwIDAQABozIwMDAdBgNVHQ4EFgQUwmbHo8YbiR463GRKSLL3eIKyvDkwDwYD\n" + + "VR0TAQH/BAUwAwIBADANBgkqhkiG9w0BAQUFAAOCAQEAydijH3rbnvpBDB/30w2PCGMT7O0N/XYM\n" + + "wBtUidqa4NFumJrNrccx5Ehp4UP66BfP61HW8h2U/EekYfOsZyyWd4KnsDD6ycR8h/WvpK3BC2cn\n" + + "I299wbqCEZmk5ZFFaEIDHdLAdgMCuxJkAzy9mMrWEa05Soxi2/ZXdrU9nXo5dzuPGYlirVPDHl7r\n" + + "/urBxD6HVX3ObQJRJ7r/nAWyUVdX3/biJaDRsydftOpGU6Gi5c1JK4MWIz8Bsjh6mEjCsVatbPPl\n" + + "yygGiJbDZfAvN2XoaVEBii2GDDCWfaFwPVPYlNTvjkUkMP8YThlMsiJ8Q4693XoLOL94GpNlCfUg\n" + + "7n+KOQ=="; this.context = Mockito.mock(Context.class); @@ -80,7 +90,7 @@ public class DeviceTest { SharedPreferences.Editor editor = deviceSettings.edit(); editor.putString("deviceName", name); editor.putString("deviceType", Device.DeviceType.Phone.toString()); - editor.putString("publicKey", Base64.encodeToString(keyPair.getPublic().getEncoded(), 0).trim() + "\n"); + editor.putString("certificate", encodedCertificate); editor.apply(); Mockito.when(context.getSharedPreferences(eq(deviceId), eq(Context.MODE_PRIVATE))).thenReturn(deviceSettings); @@ -115,23 +125,25 @@ public class DeviceTest { // Basic paired device testing @Test - public void testDevice() { + public void testDevice() throws CertificateException { Device device = new Device(context, "testDevice"); assertEquals(device.getDeviceId(), "testDevice"); assertEquals(device.getDeviceType(), Device.DeviceType.Phone); assertEquals(device.getName(), "Test Device"); assertTrue(device.isPaired()); + assertNotNull(device.certificate); } - public void testPairingDoneWithCertificate() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { + public void testPairingDone() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, CertificateException { NetworkPacket fakeNetworkPacket = new NetworkPacket(NetworkPacket.PACKET_TYPE_IDENTITY); - fakeNetworkPacket.set("deviceId", "unpairedTestDevice"); + String deviceId = "unpairedTestDevice"; + fakeNetworkPacket.set("deviceId", deviceId); fakeNetworkPacket.set("deviceName", "Unpaired Test Device"); fakeNetworkPacket.set("protocolVersion", DeviceHelper.ProtocolVersion); fakeNetworkPacket.set("deviceType", Device.DeviceType.Phone.toString()); - fakeNetworkPacket.set("certificate", + String certificateString = "MIIDVzCCAj+gAwIBAgIBCjANBgkqhkiG9w0BAQUFADBVMS8wLQYDVQQDDCZfZGExNzlhOTFfZjA2\n" + "NF80NzhlX2JlOGNfMTkzNWQ3NTQ0ZDU0XzEMMAoGA1UECgwDS0RFMRQwEgYDVQQLDAtLZGUgY29u\n" + "bmVjdDAeFw0xNTA2MDMxMzE0MzhaFw0yNTA2MDMxMzE0MzhaMFUxLzAtBgNVBAMMJl9kYTE3OWE5\n" + @@ -147,16 +159,18 @@ public class DeviceTest { "I299wbqCEZmk5ZFFaEIDHdLAdgMCuxJkAzy9mMrWEa05Soxi2/ZXdrU9nXo5dzuPGYlirVPDHl7r\n" + "/urBxD6HVX3ObQJRJ7r/nAWyUVdX3/biJaDRsydftOpGU6Gi5c1JK4MWIz8Bsjh6mEjCsVatbPPl\n" + "yygGiJbDZfAvN2XoaVEBii2GDDCWfaFwPVPYlNTvjkUkMP8YThlMsiJ8Q4693XoLOL94GpNlCfUg\n" + - "7n+KOQ=="); + "7n+KOQ=="; + byte[] certificateBytes = Base64.decode(certificateString, 0); + Certificate certificate = SslHelper.parseCertificate(certificateBytes); LanLinkProvider linkProvider = Mockito.mock(LanLinkProvider.class); Mockito.when(linkProvider.getName()).thenReturn("LanLinkProvider"); LanLink link = Mockito.mock(LanLink.class); Mockito.when(link.getLinkProvider()).thenReturn(linkProvider); - Device device = new Device(context, fakeNetworkPacket, link); + Device device = new Device(context, deviceId, certificate, fakeNetworkPacket, link); assertNotNull(device); - assertEquals(device.getDeviceId(), "unpairedTestDevice"); + assertEquals(device.getDeviceId(), deviceId); assertEquals(device.getName(), "Unpaired Test Device"); assertEquals(device.getDeviceType(), Device.DeviceType.Phone); assertNotNull(device.certificate); @@ -180,7 +194,7 @@ public class DeviceTest { } @Test - public void testUnpair() { + public void testUnpair() throws CertificateException { PairingHandler.PairingCallback pairingCallback = Mockito.mock(PairingHandler.PairingCallback.class); Device device = new Device(context, "testDevice"); device.addPairingCallback(pairingCallback);