aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java')
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java119
1 files changed, 82 insertions, 37 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index 581ddb378..503fed3c9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -17,24 +17,24 @@
package org.sufficientlysecure.keychain.provider;
+import java.security.SignatureException;
+import org.spongycastle.bcpg.ArmoredOutputStream;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
-import android.database.CursorWindow;
-import android.database.CursorWrapper;
import android.database.DatabaseUtils;
-import android.database.sqlite.SQLiteCursor;
import android.net.Uri;
import android.os.RemoteException;
-import org.spongycastle.bcpg.ArmoredOutputStream;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.sufficientlysecure.keychain.Constants;
@@ -46,6 +46,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
+import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.remote.AccountSettings;
import org.sufficientlysecure.keychain.remote.AppSettings;
import org.sufficientlysecure.keychain.util.IterableIterator;
@@ -56,6 +57,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
+import java.util.Map;
import java.util.HashSet;
import java.util.Set;
@@ -104,9 +106,6 @@ public class ProviderHelper {
return getGenericData(context, KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), proj, types);
}
- /** Find the master key id related to a given query. The id will either be extracted from the
- * query, which should work for all specific /key_rings/ queries, or will be queried if it can't.
- */
public static long getMasterKeyId(Context context, Uri queryUri) {
// try extracting from the uri first
String firstSegment = queryUri.getPathSegments().get(1);
@@ -123,25 +122,31 @@ public class ProviderHelper {
return 0L;
}
- public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) {
+ public static Map<Long, PGPKeyRing> getPGPKeyRings(Context context, Uri queryUri) {
Cursor cursor = context.getContentResolver().query(queryUri,
- new String[]{KeyRings._ID, KeyRingData.KEY_RING_DATA}, null, null, null);
-
- PGPKeyRing keyRing = null;
- if (cursor != null && cursor.moveToFirst()) {
- int keyRingDataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
+ new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA },
+ null, null, null);
- byte[] data = cursor.getBlob(keyRingDataCol);
+ Map<Long, PGPKeyRing> result = new HashMap<Long, PGPKeyRing>(cursor.getCount());
+ if (cursor != null && cursor.moveToFirst()) do {
+ long masterKeyId = cursor.getLong(0);
+ byte[] data = cursor.getBlob(1);
if (data != null) {
- keyRing = PgpConversionHelper.BytesToPGPKeyRing(data);
+ result.put(masterKeyId, PgpConversionHelper.BytesToPGPKeyRing(data));
}
- }
+ } while(cursor.moveToNext());
if (cursor != null) {
cursor.close();
}
- return keyRing;
+ return result;
+ }
+ public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) {
+ Map<Long, PGPKeyRing> result = getPGPKeyRings(context, queryUri);
+ if(result.isEmpty())
+ return null;
+ return result.values().iterator().next();
}
public static PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(Context context, long keyId) {
@@ -216,19 +221,49 @@ public class ProviderHelper {
++rank;
}
+ // get a list of owned secret keys, for verification filtering
+ Map<Long, PGPKeyRing> allKeyRings = getPGPKeyRings(context, KeyRingData.buildSecretKeyRingUri());
+
int userIdRank = 0;
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
operations.add(buildUserIdOperations(context, masterKeyId, userId, userIdRank));
- ++userIdRank;
- }
- for (PGPSignature certification :
- new IterableIterator<PGPSignature>(
- masterKey.getSignaturesOfType(PGPSignature.POSITIVE_CERTIFICATION))) {
- // TODO: how to do this??
- // we need to verify the signatures again and again when they are displayed...
-// if (certification.verify
-// operations.add(buildPublicKeyOperations(context, keyRingRowId, key, rank));
+ // look through signatures for this specific key
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(
+ masterKey.getSignaturesForID(userId))) {
+ long certId = cert.getKeyID();
+ boolean verified = false;
+ // do verify signatures from our own private keys
+ if(allKeyRings.containsKey(certId)) try {
+ // mark them as verified
+ cert.init(
+ new JcaPGPContentVerifierBuilderProvider().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME),
+ allKeyRings.get(certId).getPublicKey());
+ verified = cert.verifyCertification(userId, masterKey);
+ Log.d(Constants.TAG, "Verified sig for " + userId + " " + verified + " from "
+ + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID())
+ );
+ } catch(SignatureException e) {
+ Log.e(Constants.TAG, "Signature verification failed! "
+ + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID())
+ + " from "
+ + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e);
+ } catch(PGPException e) {
+ Log.e(Constants.TAG, "Signature verification failed! "
+ + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID())
+ + " from "
+ + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e);
+ }
+ Log.d(Constants.TAG, "sig for " + userId + " from "
+ + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID())
+ );
+ // regardless of verification, save the certification
+ operations.add(buildCertOperations(
+ context, masterKeyId, userIdRank, masterKey.getKeyID(), cert, verified));
+ }
+
+ ++userIdRank;
}
try {
@@ -311,11 +346,27 @@ public class ProviderHelper {
}
/**
- * Build ContentProviderOperation to add PGPSecretKey to database corresponding to a keyRing
+ * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing
*/
- private static ContentProviderOperation buildSecretKeyOperations(Context context,
- long masterKeyId, PGPSecretKey key, int rank) throws IOException {
- return buildPublicKeyOperations(context, masterKeyId, key.getPublicKey(), rank);
+ private static ContentProviderOperation buildCertOperations(Context context,
+ long masterKeyId,
+ int rank,
+ long keyId,
+ PGPSignature cert,
+ boolean verified)
+ throws IOException {
+ ContentValues values = new ContentValues();
+ values.put(Certs.MASTER_KEY_ID, masterKeyId);
+ values.put(Certs.RANK, rank);
+ values.put(Certs.KEY_ID_CERTIFIER, cert.getKeyID());
+ values.put(Certs.CREATION, cert.getCreationTime().getTime() / 1000);
+ values.put(Certs.EXPIRY, (String) null); // TODO
+ values.put(Certs.VERIFIED, verified);
+ values.put(Certs.KEY_DATA, cert.getEncoded());
+
+ Uri uri = Certs.buildCertsUri(Long.toString(masterKeyId));
+
+ return ContentProviderOperation.newInsert(uri).withValues(values).build();
}
/**
@@ -333,12 +384,6 @@ public class ProviderHelper {
return ContentProviderOperation.newInsert(uri).withValues(values).build();
}
- public static boolean hasSecretKeyByMasterKeyId(Context context, long masterKeyId) {
- Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
- // see if we can get our master key id back from the uri
- return getMasterKeyId(context, queryUri) == masterKeyId;
- }
-
public static ArrayList<String> getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) {
ArrayList<String> output = new ArrayList<String>();