Make it possible to start the headless app on MacOS.

The app is still non-functional because we don't have a Tor plugin.
This commit is contained in:
akwizgran
2018-11-23 12:52:40 +00:00
parent c09abdb088
commit 61276c81d2
7 changed files with 72 additions and 68 deletions

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.system; package org.briarproject.bramble.system;
import android.annotation.SuppressLint;
import android.app.Application; import android.app.Application;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
@@ -26,7 +27,7 @@ import static android.provider.Settings.Secure.ANDROID_ID;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
class AndroidSecureRandomProvider extends LinuxSecureRandomProvider { class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
private static final int SEED_LENGTH = 32; private static final int SEED_LENGTH = 32;
@@ -37,6 +38,7 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
appContext = app.getApplicationContext(); appContext = app.getApplicationContext();
} }
@SuppressLint("HardwareIds")
@Override @Override
protected void writeToEntropyPool(DataOutputStream out) throws IOException { protected void writeToEntropyPool(DataOutputStream out) throws IOException {
super.writeToEntropyPool(out); super.writeToEntropyPool(out);
@@ -49,12 +51,14 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
String id = Settings.Secure.getString(contentResolver, ANDROID_ID); String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
if (id != null) out.writeUTF(id); if (id != null) out.writeUTF(id);
Parcel parcel = Parcel.obtain(); Parcel parcel = Parcel.obtain();
WifiManager wm = WifiManager wm = (WifiManager) appContext.getApplicationContext()
(WifiManager) appContext.getSystemService(WIFI_SERVICE); .getSystemService(WIFI_SERVICE);
List<WifiConfiguration> configs = wm.getConfiguredNetworks(); if (wm != null) {
if (configs != null) { List<WifiConfiguration> configs = wm.getConfiguredNetworks();
for (WifiConfiguration config : configs) if (configs != null) {
parcel.writeParcelable(config, 0); for (WifiConfiguration config : configs)
parcel.writeParcelable(config, 0);
}
} }
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt != null) { if (bt != null) {
@@ -77,13 +81,13 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html // Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
private void applyOpenSslFix() { private void applyOpenSslFix() {
byte[] seed = new LinuxSecureRandomSpi().engineGenerateSeed( byte[] seed = new UnixSecureRandomSpi().engineGenerateSeed(
SEED_LENGTH); SEED_LENGTH);
try { try {
// Seed the OpenSSL PRNG // Seed the OpenSSL PRNG
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto") Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_seed", byte[].class) .getMethod("RAND_seed", byte[].class)
.invoke(null, seed); .invoke(null, (Object) seed);
// Mix the output of the Linux PRNG into the OpenSSL PRNG // Mix the output of the Linux PRNG into the OpenSSL PRNG
int bytesRead = (Integer) Class.forName( int bytesRead = (Integer) Class.forName(
"org.apache.harmony.xnet.provider.jsse.NativeCrypto") "org.apache.harmony.xnet.provider.jsse.NativeCrypto")

View File

@@ -13,32 +13,33 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
class LinuxSecureRandomProvider extends AbstractSecureRandomProvider { class UnixSecureRandomProvider extends AbstractSecureRandomProvider {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(LinuxSecureRandomProvider.class.getName()); getLogger(UnixSecureRandomProvider.class.getName());
private static final File RANDOM_DEVICE = new File("/dev/urandom"); private static final File RANDOM_DEVICE = new File("/dev/urandom");
private final AtomicBoolean seeded = new AtomicBoolean(false); private final AtomicBoolean seeded = new AtomicBoolean(false);
private final File outputDevice; private final File outputDevice;
LinuxSecureRandomProvider() { UnixSecureRandomProvider() {
this(RANDOM_DEVICE); this(RANDOM_DEVICE);
} }
LinuxSecureRandomProvider(File outputDevice) { UnixSecureRandomProvider(File outputDevice) {
this.outputDevice = outputDevice; this.outputDevice = outputDevice;
} }
@Override @Override
public Provider getProvider() { public Provider getProvider() {
if (!seeded.getAndSet(true)) writeSeed(); if (!seeded.getAndSet(true)) writeSeed();
return new LinuxProvider(); return new UnixProvider();
} }
protected void writeSeed() { protected void writeSeed() {
@@ -55,15 +56,15 @@ class LinuxSecureRandomProvider extends AbstractSecureRandomProvider {
} }
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html // Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
private static class LinuxProvider extends Provider { private static class UnixProvider extends Provider {
private LinuxProvider() { private UnixProvider() {
super("LinuxPRNG", 1.1, "A Linux-specific PRNG using /dev/urandom"); super("UnixPRNG", 1.0, "A Unix-specific PRNG using /dev/urandom");
// Although /dev/urandom is not a SHA-1 PRNG, some callers // Although /dev/urandom is not a SHA-1 PRNG, some callers
// explicitly request a SHA1PRNG SecureRandom and we need to // explicitly request a SHA1PRNG SecureRandom and we need to
// prevent them from getting the default implementation whose // prevent them from getting the default implementation whose
// output may have low entropy. // output may have low entropy.
put("SecureRandom.SHA1PRNG", LinuxSecureRandomSpi.class.getName()); put("SecureRandom.SHA1PRNG", UnixSecureRandomSpi.class.getName());
put("SecureRandom.SHA1PRNG ImplementedIn", "Software"); put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
} }
} }

View File

@@ -10,22 +10,24 @@ import java.security.SecureRandomSpi;
import java.util.logging.Logger; import java.util.logging.Logger;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
public class LinuxSecureRandomSpi extends SecureRandomSpi { public class UnixSecureRandomSpi extends SecureRandomSpi {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(LinuxSecureRandomSpi.class.getName()); getLogger(UnixSecureRandomSpi.class.getName());
private static final File RANDOM_DEVICE = new File("/dev/urandom"); private static final File RANDOM_DEVICE = new File("/dev/urandom");
private final File inputDevice, outputDevice; private final File inputDevice, outputDevice;
public LinuxSecureRandomSpi() { @SuppressWarnings("WeakerAccess")
public UnixSecureRandomSpi() {
this(RANDOM_DEVICE, RANDOM_DEVICE); this(RANDOM_DEVICE, RANDOM_DEVICE);
} }
LinuxSecureRandomSpi(File inputDevice, File outputDevice) { UnixSecureRandomSpi(File inputDevice, File outputDevice) {
this.inputDevice = inputDevice; this.inputDevice = inputDevice;
this.outputDevice = outputDevice; this.outputDevice = outputDevice;
} }

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.system; package org.briarproject.bramble.system;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.TestUtils;
import org.briarproject.bramble.util.OsUtils; import org.briarproject.bramble.util.OsUtils;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@@ -10,48 +9,48 @@ import org.junit.Test;
import java.io.File; import java.io.File;
import java.security.Provider; import java.security.Provider;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
public class LinuxSecureRandomProviderTest extends BrambleTestCase { public class UnixSecureRandomProviderTest extends BrambleTestCase {
private final File testDir = TestUtils.getTestDirectory(); private final File testDir = getTestDirectory();
@Before @Before
public void setUp() { public void setUp() {
testDir.mkdirs(); assumeTrue(OsUtils.isLinux() || OsUtils.isMac());
assertTrue(testDir.mkdirs());
} }
@Test @Test
public void testGetProviderWritesToRandomDeviceOnFirstCall() public void testGetProviderWritesToRandomDeviceOnFirstCall()
throws Exception { throws Exception {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
// Redirect the provider's output to a file // Redirect the provider's output to a file
File urandom = new File(testDir, "urandom"); File urandom = new File(testDir, "urandom");
urandom.delete(); if (urandom.exists()) assertTrue(urandom.delete());
assertTrue(urandom.createNewFile()); assertTrue(urandom.createNewFile());
assertEquals(0, urandom.length()); assertEquals(0, urandom.length());
LinuxSecureRandomProvider p = new LinuxSecureRandomProvider(urandom); UnixSecureRandomProvider p = new UnixSecureRandomProvider(urandom);
// Getting a provider should write entropy to the file // Getting a provider should write entropy to the file
Provider provider = p.getProvider(); Provider provider = p.getProvider();
assertNotNull(provider); assertNotNull(provider);
assertEquals("LinuxPRNG", provider.getName()); assertEquals("UnixPRNG", provider.getName());
// There should be at least 16 bytes from the clock, 8 from the runtime // There should be at least 16 bytes from the clock, 8 from the runtime
long length = urandom.length(); long length = urandom.length();
assertTrue(length >= 24); assertTrue(length >= 24);
// Getting another provider should not write to the file again // Getting another provider should not write to the file again
provider = p.getProvider(); provider = p.getProvider();
assertNotNull(provider); assertNotNull(provider);
assertEquals("LinuxPRNG", provider.getName()); assertEquals("UnixPRNG", provider.getName());
assertEquals(length, urandom.length()); assertEquals(length, urandom.length());
} }
@After @After
public void tearDown() { public void tearDown() {
TestUtils.deleteTestDirectory(testDir); deleteTestDirectory(testDir);
} }
} }

View File

@@ -15,31 +15,31 @@ import java.io.FileOutputStream;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
public class LinuxSecureRandomSpiTest extends BrambleTestCase { public class UnixSecureRandomSpiTest extends BrambleTestCase {
private static final File RANDOM_DEVICE = new File("/dev/urandom"); private static final File RANDOM_DEVICE = new File("/dev/urandom");
private static final int SEED_BYTES = 32; private static final int SEED_BYTES = 32;
private final File testDir = TestUtils.getTestDirectory(); private final File testDir = getTestDirectory();
@Before @Before
public void setUp() { public void setUp() {
testDir.mkdirs(); assumeTrue(OsUtils.isLinux() || OsUtils.isMac());
assertTrue(testDir.mkdirs());
} }
@Test @Test
public void testSeedsAreDistinct() { public void testSeedsAreDistinct() {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
Set<Bytes> seeds = new HashSet<>(); Set<Bytes> seeds = new HashSet<>();
LinuxSecureRandomSpi engine = new LinuxSecureRandomSpi(); UnixSecureRandomSpi engine = new UnixSecureRandomSpi();
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
byte[] seed = engine.engineGenerateSeed(SEED_BYTES); byte[] seed = engine.engineGenerateSeed(SEED_BYTES);
assertEquals(SEED_BYTES, seed.length); assertEquals(SEED_BYTES, seed.length);
@@ -49,19 +49,15 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
@Test @Test
public void testEngineSetSeedWritesToRandomDevice() throws Exception { public void testEngineSetSeedWritesToRandomDevice() throws Exception {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
// Redirect the engine's output to a file // Redirect the engine's output to a file
File urandom = new File(testDir, "urandom"); File urandom = new File(testDir, "urandom");
urandom.delete(); if (urandom.exists()) assertTrue(urandom.delete());
assertTrue(urandom.createNewFile()); assertTrue(urandom.createNewFile());
assertEquals(0, urandom.length()); assertEquals(0, urandom.length());
// Generate a seed // Generate a seed
byte[] seed = TestUtils.getRandomBytes(SEED_BYTES); byte[] seed = TestUtils.getRandomBytes(SEED_BYTES);
// Check that the engine writes the seed to the file // Check that the engine writes the seed to the file
LinuxSecureRandomSpi engine = new LinuxSecureRandomSpi(RANDOM_DEVICE, UnixSecureRandomSpi engine = new UnixSecureRandomSpi(RANDOM_DEVICE,
urandom); urandom);
engine.engineSetSeed(seed); engine.engineSetSeed(seed);
assertEquals(SEED_BYTES, urandom.length()); assertEquals(SEED_BYTES, urandom.length());
@@ -74,15 +70,11 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
@Test @Test
public void testEngineNextBytesReadsFromRandomDevice() throws Exception { public void testEngineNextBytesReadsFromRandomDevice() throws Exception {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
// Generate some entropy // Generate some entropy
byte[] entropy = TestUtils.getRandomBytes(SEED_BYTES); byte[] entropy = TestUtils.getRandomBytes(SEED_BYTES);
// Write the entropy to a file // Write the entropy to a file
File urandom = new File(testDir, "urandom"); File urandom = new File(testDir, "urandom");
urandom.delete(); if (urandom.exists()) assertTrue(urandom.delete());
FileOutputStream out = new FileOutputStream(urandom); FileOutputStream out = new FileOutputStream(urandom);
out.write(entropy); out.write(entropy);
out.flush(); out.flush();
@@ -90,7 +82,7 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
assertTrue(urandom.exists()); assertTrue(urandom.exists());
assertEquals(SEED_BYTES, urandom.length()); assertEquals(SEED_BYTES, urandom.length());
// Check that the engine reads from the file // Check that the engine reads from the file
LinuxSecureRandomSpi engine = new LinuxSecureRandomSpi(urandom, UnixSecureRandomSpi engine = new UnixSecureRandomSpi(urandom,
RANDOM_DEVICE); RANDOM_DEVICE);
byte[] b = new byte[SEED_BYTES]; byte[] b = new byte[SEED_BYTES];
engine.engineNextBytes(b); engine.engineNextBytes(b);
@@ -99,15 +91,11 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
@Test @Test
public void testEngineGenerateSeedReadsFromRandomDevice() throws Exception { public void testEngineGenerateSeedReadsFromRandomDevice() throws Exception {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
// Generate some entropy // Generate some entropy
byte[] entropy = TestUtils.getRandomBytes(SEED_BYTES); byte[] entropy = TestUtils.getRandomBytes(SEED_BYTES);
// Write the entropy to a file // Write the entropy to a file
File urandom = new File(testDir, "urandom"); File urandom = new File(testDir, "urandom");
urandom.delete(); if (urandom.exists()) assertTrue(urandom.delete());
FileOutputStream out = new FileOutputStream(urandom); FileOutputStream out = new FileOutputStream(urandom);
out.write(entropy); out.write(entropy);
out.flush(); out.flush();
@@ -115,7 +103,7 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
assertTrue(urandom.exists()); assertTrue(urandom.exists());
assertEquals(SEED_BYTES, urandom.length()); assertEquals(SEED_BYTES, urandom.length());
// Check that the engine reads from the file // Check that the engine reads from the file
LinuxSecureRandomSpi engine = new LinuxSecureRandomSpi(urandom, UnixSecureRandomSpi engine = new UnixSecureRandomSpi(urandom,
RANDOM_DEVICE); RANDOM_DEVICE);
byte[] b = engine.engineGenerateSeed(SEED_BYTES); byte[] b = engine.engineGenerateSeed(SEED_BYTES);
assertArrayEquals(entropy, b); assertArrayEquals(entropy, b);
@@ -123,6 +111,6 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
@After @After
public void tearDown() { public void tearDown() {
TestUtils.deleteTestDirectory(testDir); deleteTestDirectory(testDir);
} }
} }

View File

@@ -14,6 +14,9 @@ public class DesktopSecureRandomModule {
@Provides @Provides
@Singleton @Singleton
SecureRandomProvider provideSecureRandomProvider() { SecureRandomProvider provideSecureRandomProvider() {
return OsUtils.isLinux() ? new LinuxSecureRandomProvider() : null; if (OsUtils.isLinux() || OsUtils.isMac())
return new UnixSecureRandomProvider();
// TODO: Create a secure random provider for Windows
throw new UnsupportedOperationException();
} }
} }

View File

@@ -26,6 +26,7 @@ import org.briarproject.bramble.plugin.tor.CircumventionModule
import org.briarproject.bramble.plugin.tor.CircumventionProvider import org.briarproject.bramble.plugin.tor.CircumventionProvider
import org.briarproject.bramble.plugin.tor.LinuxTorPluginFactory import org.briarproject.bramble.plugin.tor.LinuxTorPluginFactory
import org.briarproject.bramble.system.JavaSystemModule import org.briarproject.bramble.system.JavaSystemModule
import org.briarproject.bramble.util.OsUtils
import org.briarproject.bramble.util.StringUtils.fromHexString import org.briarproject.bramble.util.StringUtils.fromHexString
import org.briarproject.briar.headless.blogs.HeadlessBlogModule import org.briarproject.briar.headless.blogs.HeadlessBlogModule
import org.briarproject.briar.headless.contact.HeadlessContactModule import org.briarproject.briar.headless.contact.HeadlessContactModule
@@ -70,11 +71,17 @@ internal class HeadlessModule(private val appDir: File) {
circumventionProvider: CircumventionProvider, batteryManager: BatteryManager, clock: Clock circumventionProvider: CircumventionProvider, batteryManager: BatteryManager, clock: Clock
): PluginConfig { ): PluginConfig {
val torDirectory = File(appDir, "tor") val torDirectory = File(appDir, "tor")
val tor = LinuxTorPluginFactory( val duplex: List<DuplexPluginFactory>
ioExecutor, networkManager, locationUtils, eventBus, torSocketFactory, backoffFactory, if (OsUtils.isLinux()) {
resourceProvider, circumventionProvider, batteryManager, clock, torDirectory val tor = LinuxTorPluginFactory(
) ioExecutor, networkManager, locationUtils, eventBus,
val duplex = listOf<DuplexPluginFactory>(tor) torSocketFactory, backoffFactory, resourceProvider, circumventionProvider,
batteryManager, clock, torDirectory
)
duplex = listOf(tor)
} else {
duplex = emptyList()
}
return object : PluginConfig { return object : PluginConfig {
override fun getDuplexFactories(): Collection<DuplexPluginFactory> { override fun getDuplexFactories(): Collection<DuplexPluginFactory> {
return duplex return duplex