Merge branch 'small-swap-fixes' into 'master'
Small swap fixes These are a few fixes I found while debugging the new swap stuff. The `repo.fingerprint` commit is quite important since that is the code that provides the core of FDroid's security model. See merge request !142
This commit is contained in:
commit
4fb173e364
@ -2,6 +2,7 @@ package javax.jmdns.impl;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
@ -21,8 +22,21 @@ public class FDroidServiceInfo extends ServiceInfoImpl implements Parcelable {
|
||||
super(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fingerprint of the signing key, or {@code null} if it is not set.
|
||||
*/
|
||||
public String getFingerprint() {
|
||||
return getPropertyString("fingerprint");
|
||||
// getPropertyString() will return "true" if the value is a zero-length byte array
|
||||
// so we just do a custom version using getPropertyBytes()
|
||||
byte[] data = getPropertyBytes("fingerprint");
|
||||
if (data == null || data.length == 0) {
|
||||
return null;
|
||||
}
|
||||
String fingerprint = this.readUTF(data, 0, data.length);
|
||||
if (TextUtils.isEmpty(fingerprint)) {
|
||||
return null;
|
||||
}
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
public String getRepoAddress() {
|
||||
|
@ -36,6 +36,14 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
/**
|
||||
* Handles getting the index metadata for an app repo, then verifying the
|
||||
* signature on the index metdata, implementing as a JAR signature.
|
||||
* <p/>
|
||||
* <b>WARNING</b>: this class is the central piece of the entire security model of
|
||||
* FDroid! Avoid modifying it when possible, if you absolutely must, be very,
|
||||
* very careful with the changes that you are making!
|
||||
*/
|
||||
public class RepoUpdater {
|
||||
|
||||
private static final String TAG = "RepoUpdater";
|
||||
@ -280,7 +288,8 @@ public class RepoUpdater {
|
||||
* actually in the index.jar itself. If no fingerprint, just store the
|
||||
* signing certificate */
|
||||
boolean trustNewSigningCertificate = false;
|
||||
if (TextUtils.isEmpty(repo.fingerprint)) {
|
||||
// If the fingerprint has never been set, it will be null (never "" or something else)
|
||||
if (repo.fingerprint == null) {
|
||||
// no info to check things are valid, so just Trust On First Use
|
||||
trustNewSigningCertificate = true;
|
||||
} else {
|
||||
@ -290,7 +299,8 @@ public class RepoUpdater {
|
||||
&& repo.fingerprint.equalsIgnoreCase(fingerprintFromJar)) {
|
||||
trustNewSigningCertificate = true;
|
||||
} else {
|
||||
throw new UpdateException(repo, "Supplied certificate fingerprint does not match!");
|
||||
throw new UpdateException(repo, "Supplied certificate fingerprint does not match: '"
|
||||
+ repo.fingerprint + "' '" + fingerprintFromIndexXml + "' '" + fingerprintFromJar + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,13 +19,21 @@ public class Repo extends ValueObject {
|
||||
public String address;
|
||||
public String name;
|
||||
public String description;
|
||||
public int version; // index version, i.e. what fdroidserver built it - 0 if not specified
|
||||
/** index version, i.e. what fdroidserver built it - 0 if not specified */
|
||||
public int version;
|
||||
public boolean inuse;
|
||||
public int priority;
|
||||
public String pubkey; // null for an unsigned repo
|
||||
public String fingerprint; // always null for an unsigned repo
|
||||
public int maxage; // maximum age of index that will be accepted - 0 for any
|
||||
public String lastetag; // last etag we updated from, null forces update
|
||||
/** The signing certificate, {@code null} for a newly added repo */
|
||||
public String pubkey;
|
||||
/**
|
||||
* The SHA1 fingerprint of {@link #pubkey}, set to {@code null} when a
|
||||
* newly added repo did not include fingerprint. It should never be an
|
||||
* empty {@link String}, i.e. {@code ""} */
|
||||
public String fingerprint;
|
||||
/** maximum age of index that will be accepted - 0 for any */
|
||||
public int maxage;
|
||||
/** last etag we updated from, null forces update */
|
||||
public String lastetag;
|
||||
public Date lastUpdated;
|
||||
public boolean isSwap;
|
||||
|
||||
|
@ -345,11 +345,13 @@ public class LocalRepoManager {
|
||||
serializer = XmlPullParserFactory.newInstance().newSerializer();
|
||||
}
|
||||
|
||||
public void build(Writer output) throws IOException, LocalRepoKeyStore.InitException {
|
||||
public void build(File file) throws IOException, LocalRepoKeyStore.InitException {
|
||||
Writer output = new FileWriter(file);
|
||||
serializer.setOutput(output);
|
||||
serializer.startDocument(null, null);
|
||||
tagFdroid();
|
||||
serializer.endDocument();
|
||||
output.close();
|
||||
}
|
||||
|
||||
private void tagFdroid() throws IOException, LocalRepoKeyStore.InitException {
|
||||
@ -485,16 +487,12 @@ public class LocalRepoManager {
|
||||
|
||||
public void writeIndexJar() throws IOException {
|
||||
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
writer = new FileWriter(xmlIndex);
|
||||
new IndexXmlBuilder(context, apps).build(writer);
|
||||
new IndexXmlBuilder(context, apps).build(xmlIndex);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Could not write index jar", e);
|
||||
Toast.makeText(context, R.string.failed_to_create_index, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
} finally {
|
||||
Utils.closeQuietly(writer);
|
||||
}
|
||||
|
||||
BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(xmlIndexJarUnsigned));
|
||||
|
@ -259,6 +259,8 @@ public class SwapService extends Service {
|
||||
values.put(RepoProvider.DataColumns.NAME, peer.getName());
|
||||
values.put(RepoProvider.DataColumns.ADDRESS, peer.getRepoAddress());
|
||||
values.put(RepoProvider.DataColumns.DESCRIPTION, "");
|
||||
String fingerprint = peer.getFingerprint();
|
||||
if (!TextUtils.isEmpty(fingerprint))
|
||||
values.put(RepoProvider.DataColumns.FINGERPRINT, peer.getFingerprint());
|
||||
values.put(RepoProvider.DataColumns.IN_USE, true);
|
||||
values.put(RepoProvider.DataColumns.IS_SWAP, true);
|
||||
|
@ -7,6 +7,7 @@ import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.localrepo.type.BluetoothSwap;
|
||||
|
||||
public class BluetoothPeer implements Peer {
|
||||
private static final String TAG = "BluetoothPeer";
|
||||
|
||||
private BluetoothDevice device;
|
||||
|
||||
@ -40,13 +41,15 @@ public class BluetoothPeer implements Peer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Bluetooth will exclusively be TOFU. Once a device is connected to a bluetooth socket,
|
||||
* if we trust it enough to accept a fingerprint from it somehow, then we may as well trust it
|
||||
* enough to receive an index from it that contains a fingerprint we can use.
|
||||
* Return the fingerprint of the signing key, or {@code null} if it is not set.
|
||||
* <p/>
|
||||
* This is not yet stored for Bluetooth connections. Once a device is connected to a bluetooth
|
||||
* socket, if we trust it enough to accept a fingerprint from it somehow, then we may as well
|
||||
* trust it enough to receive an index from it that contains a fingerprint we can use.
|
||||
*/
|
||||
@Override
|
||||
public String getFingerprint() {
|
||||
return "";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,6 +41,9 @@ public class BonjourPeer extends WifiPeer {
|
||||
return serviceInfo.getRepoAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fingerprint of the signing key, or {@code null} if it is not set.
|
||||
*/
|
||||
@Override
|
||||
public String getFingerprint() {
|
||||
return serviceInfo.getFingerprint();
|
||||
|
@ -14,7 +14,7 @@ import org.fdroid.fdroid.net.bluetooth.BluetoothServer;
|
||||
|
||||
public class BluetoothSwap extends SwapType {
|
||||
|
||||
private static final String TAG = "BluetoothBroadcastType";
|
||||
private static final String TAG = "BluetoothSwap";
|
||||
public final static String BLUETOOTH_NAME_TAG = "FDroid:";
|
||||
|
||||
private static BluetoothSwap mInstance = null;
|
||||
|
@ -20,7 +20,7 @@ import javax.jmdns.ServiceInfo;
|
||||
*/
|
||||
public class BonjourBroadcast extends SwapType {
|
||||
|
||||
private static final String TAG = "BonjourSwapService";
|
||||
private static final String TAG = "BonjourBroadcast";
|
||||
|
||||
private JmDNS jmdns;
|
||||
private ServiceInfo pairService;
|
||||
|
@ -21,7 +21,7 @@ import java.util.Random;
|
||||
|
||||
public class WifiSwap extends SwapType {
|
||||
|
||||
private static final String TAG = "WebServerType";
|
||||
private static final String TAG = "WifiSwap";
|
||||
|
||||
private Handler webServerThreadHandler = null;
|
||||
private LocalHTTPD localHttpd;
|
||||
|
@ -207,7 +207,8 @@ public class WifiStateChangeService extends Service {
|
||||
// the following methods were not added until android-9/Gingerbread
|
||||
for (InterfaceAddress address : netIf.getInterfaceAddresses()) {
|
||||
if (inetAddress.equals(address.getAddress()) && !TextUtils.isEmpty(FDroidApp.ipAddressString)) {
|
||||
String cidr = String.format("%s/%d", FDroidApp.ipAddressString, address.getNetworkPrefixLength());
|
||||
String cidr = String.format(Locale.ENGLISH, "%s/%d",
|
||||
FDroidApp.ipAddressString, address.getNetworkPrefixLength());
|
||||
FDroidApp.subnetInfo = (new SubnetUtils(cidr)).getInfo();
|
||||
break;
|
||||
}
|
||||
|
@ -84,7 +84,11 @@ public class AvailableAppsFragment extends AppListFragment implements
|
||||
// Wanted to just do this update here, but android tells
|
||||
// me that "Only the original thread that created a view
|
||||
// hierarchy can touch its views."
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
final Activity activity = getActivity();
|
||||
// this nullguard is temporary, this Fragment really needs to merged into the Activity
|
||||
if (activity == null)
|
||||
return;
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (adapter == null) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user