diff --git a/F-Droid/src/javax/jmdns/impl/FDroidServiceInfo.java b/F-Droid/src/javax/jmdns/impl/FDroidServiceInfo.java index c4fba32f3..111354994 100644 --- a/F-Droid/src/javax/jmdns/impl/FDroidServiceInfo.java +++ b/F-Droid/src/javax/jmdns/impl/FDroidServiceInfo.java @@ -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() { diff --git a/F-Droid/src/org/fdroid/fdroid/RepoUpdater.java b/F-Droid/src/org/fdroid/fdroid/RepoUpdater.java index 17b964e52..b23d28f7e 100644 --- a/F-Droid/src/org/fdroid/fdroid/RepoUpdater.java +++ b/F-Droid/src/org/fdroid/fdroid/RepoUpdater.java @@ -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. + *

+ * WARNING: 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 + "'"); } } diff --git a/F-Droid/src/org/fdroid/fdroid/data/Repo.java b/F-Droid/src/org/fdroid/fdroid/data/Repo.java index fb4cbdd06..28979ec6c 100644 --- a/F-Droid/src/org/fdroid/fdroid/data/Repo.java +++ b/F-Droid/src/org/fdroid/fdroid/data/Repo.java @@ -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; diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java index 1e5f9b708..09e9e9998 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java @@ -259,7 +259,9 @@ public class SwapService extends Service { values.put(RepoProvider.DataColumns.NAME, peer.getName()); values.put(RepoProvider.DataColumns.ADDRESS, peer.getRepoAddress()); values.put(RepoProvider.DataColumns.DESCRIPTION, ""); - values.put(RepoProvider.DataColumns.FINGERPRINT, peer.getFingerprint()); + 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); Uri uri = RepoProvider.Helper.insert(this, values); diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothPeer.java b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothPeer.java index 45261d6d5..4d12db070 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothPeer.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothPeer.java @@ -40,13 +40,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. + *

+ * 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 diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourPeer.java b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourPeer.java index def234be7..0da35cc0e 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourPeer.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourPeer.java @@ -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();