diff options
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.java | 119 |
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>(); |