certs: provider cleanup and bugfixing

This commit is contained in:
Vincent Breitmoser 2014-03-15 19:57:22 +01:00
parent 6bacb5ff51
commit 5c28da44d6
6 changed files with 75 additions and 84 deletions

View File

@ -451,6 +451,9 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "."
+ KeyRingsColumns.MASTER_KEY_ID); + KeyRingsColumns.MASTER_KEY_ID);
// this is the count of known secret keys who certified this uid
projectionMap.put("verified", "COUNT(" + Tables.KEYS + "." + Keys._ID + ") AS verified");
return projectionMap; return projectionMap;
} }
@ -659,38 +662,37 @@ public class KeychainProvider extends ContentProvider {
break; break;
case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID: case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID:
qb.setTables(Tables.USER_IDS + " INNER JOIN " + Tables.KEY_RINGS + " ON " + "("
+ Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.USER_IDS + "."
+ KeysColumns.KEY_RING_ROW_ID + " )");
qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(3));
qb.setProjectionMap(getProjectionMapForUserIds());
break;
case PUBLIC_KEY_RING_USER_ID: case PUBLIC_KEY_RING_USER_ID:
case SECRET_KEY_RING_USER_ID: case SECRET_KEY_RING_USER_ID:
qb.setTables(Tables.USER_IDS qb.setTables(Tables.USER_IDS
+ " LEFT JOIN " + Tables.CERTS + " INNER JOIN " + Tables.KEY_RINGS + " ON ("
+ " ON (" + Tables.KEY_RINGS + "." + BaseColumns._ID + " = "
+ Tables.USER_IDS + "." + KeysColumns.KEY_RING_ROW_ID
+ ") LEFT JOIN " + Tables.CERTS + " ON ("
+ Tables.USER_IDS + "." + UserIds.KEY_RING_ROW_ID + " = " + Tables.USER_IDS + "." + UserIds.KEY_RING_ROW_ID + " = "
+ Tables.CERTS + "." + Certs.KEY_RING_ROW_ID + Tables.CERTS + "." + Certs.KEY_RING_ROW_ID
+ " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = " + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = "
+ Tables.CERTS + "." + Certs.RANK + Tables.CERTS + "." + Certs.RANK
+ ") LEFT JOIN " + Tables.KEYS + " ON ("
+ Tables.KEYS + "." + Keys.KEY_ID + " = "
+ Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER
// might introduce a "trusted" flag later? for now, we simply assume
// every private key's signature is good.
+ " AND " + Tables.KEYS + "." + Keys.TYPE
+ " == " + KeyTypes.SECRET
+ ")"); + ")");
groupBy = Tables.USER_IDS + "." + UserIds.RANK; groupBy = Tables.USER_IDS + "." + UserIds.RANK;
HashMap<String, String> pmap = new HashMap<String, String>(); qb.setProjectionMap(getProjectionMapForUserIds());
pmap.put(UserIds._ID, Tables.USER_IDS + "." + UserIds._ID);
pmap.put(UserIds.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID);
pmap.put(UserIds.RANK, Tables.USER_IDS + "." + UserIds.RANK);
pmap.put("verified", "COUNT(" + Tables.CERTS + "." + Certs._ID + ") AS verified");
qb.setProjectionMap(pmap);
qb.appendWhere(Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " = "); if(match == PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID) {
qb.appendWhereEscapeString(uri.getPathSegments().get(2)); qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(3));
} else {
qb.appendWhere(Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(2));
}
break; break;
@ -728,7 +730,8 @@ public class KeychainProvider extends ContentProvider {
+ "signer." + Keys.RANK + " = 0" + "signer." + Keys.RANK + " = 0"
+ ")"); + ")");
// groupBy = Tables.USER_IDS + "." + UserIds.RANK; groupBy = Tables.CERTS + "." + Certs.RANK + ", "
+ Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER;
HashMap<String, String> pmap2 = new HashMap<String, String>(); HashMap<String, String> pmap2 = new HashMap<String, String>();
pmap2.put(Certs._ID, Tables.CERTS + "." + Certs._ID); pmap2.put(Certs._ID, Tables.CERTS + "." + Certs._ID);

View File

@ -207,7 +207,7 @@ public class ProviderHelper {
} }
// get a list of owned secret keys, for verification filtering // get a list of owned secret keys, for verification filtering
Map<Long, PGPKeyRing> allKeyRings = getPGPKeyRings(context, KeyRings.buildPublicKeyRingsUri()); Map<Long, PGPKeyRing> allKeyRings = getPGPKeyRings(context, KeyRings.buildSecretKeyRingsUri());
int userIdRank = 0; int userIdRank = 0;
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) { for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
@ -218,35 +218,34 @@ public class ProviderHelper {
masterKey.getSignaturesForID(userId))) { masterKey.getSignaturesForID(userId))) {
long certId = cert.getKeyID(); long certId = cert.getKeyID();
boolean verified = false; boolean verified = false;
// only care for signatures from our own private keys // do verify signatures from our own private keys
if(allKeyRings.containsKey(certId)) try { if(allKeyRings.containsKey(certId)) try {
// mark them as verified // mark them as verified
cert.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), allKeyRings.get(certId).getPublicKey()); cert.init(
new JcaPGPContentVerifierBuilderProvider().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME),
allKeyRings.get(certId).getPublicKey());
verified = cert.verifyCertification(userId, masterKey); verified = cert.verifyCertification(userId, masterKey);
// TODO: at this point, we only save signatures from available secret keys. Log.d(Constants.TAG, "Verified sig for " + userId + " " + verified + " from "
// should we save all? those are quite a lot of rows for info we don't really
// use. I left it out for now - it is available from key servers, so we can
// always get it later.
Log.d(Constants.TAG, "sig for " + userId + " " + verified + " from "
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()) + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID())
); );
operations.add(buildPublicCertOperations(
context, keyRingRowId, userIdRank, masterKey.getKeyID(), cert, verified));
} catch(SignatureException e) { } catch(SignatureException e) {
Log.e(Constants.TAG, "Signature verification failed.", e); Log.e(Constants.TAG, "Signature verification failed! "
} catch(PGPException e) {
Log.e(Constants.TAG, "Signature verification failed.", e);
} else {
Log.d(Constants.TAG, "ignored sig for "
+ PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID()) + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID())
+ " from " + " from "
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()) + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e);
); } catch(PGPException e) {
operations.add(buildPublicCertOperations( Log.e(Constants.TAG, "Signature verification failed! "
context, keyRingRowId, userIdRank, masterKey.getKeyID(), cert, false)); + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID())
+ " from "
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e);
} }
// if we wanted to save all, not just our own verifications Log.d(Constants.TAG, "sig for " + userId + " from "
// buildPublicCertOperations(context, keyRingRowId, rank, cert, verified); + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID())
);
// regardless of verification, save the certification
operations.add(buildPublicCertOperations(
context, keyRingRowId, userIdRank, masterKey.getKeyID(), cert, verified));
} }
++userIdRank; ++userIdRank;

View File

@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
@ -164,7 +165,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
KeychainContract.KeyRings._ID, KeychainContract.KeyRings._ID,
KeychainContract.KeyRings.MASTER_KEY_ID, KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.Keys.FINGERPRINT, KeychainContract.Keys.FINGERPRINT,
KeychainContract.UserIds.USER_ID KeychainContract.UserIds.USER_ID,
}; };
static final int INDEX_MASTER_KEY_ID = 1; static final int INDEX_MASTER_KEY_ID = 1;
static final int INDEX_FINGERPRINT = 2; static final int INDEX_FINGERPRINT = 2;
@ -174,10 +175,11 @@ public class CertifyKeyActivity extends ActionBarActivity implements
new String[]{ new String[]{
KeychainContract.UserIds._ID, KeychainContract.UserIds._ID,
KeychainContract.UserIds.USER_ID, KeychainContract.UserIds.USER_ID,
KeychainContract.UserIds.RANK KeychainContract.UserIds.RANK,
"verified"
}; };
static final String USER_IDS_SORT_ORDER = static final String USER_IDS_SORT_ORDER =
KeychainContract.UserIds.RANK + " ASC"; KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.RANK + " ASC";
@Override @Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) { public Loader<Cursor> onCreateLoader(int id, Bundle args) {

View File

@ -53,12 +53,17 @@ public class ViewCertActivity extends ActionBarActivity
KeychainContract.Certs._ID, KeychainContract.Certs._ID,
KeychainContract.Certs.KEY_ID, KeychainContract.Certs.KEY_ID,
KeychainContract.UserIds.USER_ID, KeychainContract.UserIds.USER_ID,
KeychainContract.Certs.RANK,
KeychainContract.Certs.CREATION, KeychainContract.Certs.CREATION,
KeychainContract.Certs.KEY_ID_CERTIFIER, KeychainContract.Certs.KEY_ID_CERTIFIER,
"signer_uid", "signer_uid",
KeychainContract.Certs.KEY_DATA KeychainContract.Certs.KEY_DATA
}; };
private static final int INDEX_KEY_ID = 1;
private static final int INDEX_USER_ID = 2;
private static final int INDEX_CREATION = 3;
private static final int INDEX_KEY_ID_CERTIFIER = 4;
private static final int INDEX_UID_CERTIFIER = 5;
private static final int INDEX_KEY_DATA = 6;
private Uri mDataUri; private Uri mDataUri;
@ -78,7 +83,6 @@ public class ViewCertActivity extends ActionBarActivity
mSigneeKey = (TextView) findViewById(R.id.signee_key); mSigneeKey = (TextView) findViewById(R.id.signee_key);
mSigneeUid = (TextView) findViewById(R.id.signee_uid); mSigneeUid = (TextView) findViewById(R.id.signee_uid);
mRank = (TextView) findViewById(R.id.subkey_rank);
mAlgorithm = (TextView) findViewById(R.id.algorithm); mAlgorithm = (TextView) findViewById(R.id.algorithm);
mType = (TextView) findViewById(R.id.signature_type); mType = (TextView) findViewById(R.id.signature_type);
mCreation = (TextView) findViewById(R.id.creation); mCreation = (TextView) findViewById(R.id.creation);
@ -108,29 +112,26 @@ public class ViewCertActivity extends ActionBarActivity
@Override @Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if(data.moveToFirst()) { if(data.moveToFirst()) {
String signeeKey = "0x" + PgpKeyHelper.convertKeyIdToHex(data.getLong(1)); String signeeKey = "0x" + PgpKeyHelper.convertKeyIdToHex(data.getLong(INDEX_KEY_ID));
mSigneeKey.setText(signeeKey); mSigneeKey.setText(signeeKey);
String signeeUid = data.getString(2); String signeeUid = data.getString(INDEX_USER_ID);
mSigneeUid.setText(signeeUid); mSigneeUid.setText(signeeUid);
String subkey_rank = Integer.toString(data.getInt(3)); Date creationDate = new Date(data.getLong(INDEX_CREATION) * 1000);
mRank.setText(subkey_rank);
Date creationDate = new Date(data.getLong(4) * 1000);
mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format(creationDate)); mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format(creationDate));
mSignerKeyId = data.getLong(5); mSignerKeyId = data.getLong(INDEX_KEY_ID_CERTIFIER);
String signerKey = "0x" + PgpKeyHelper.convertKeyIdToHex(mSignerKeyId); String signerKey = "0x" + PgpKeyHelper.convertKeyIdToHex(mSignerKeyId);
mSignerKey.setText(signerKey); mSignerKey.setText(signerKey);
String signerUid = data.getString(6); String signerUid = data.getString(INDEX_UID_CERTIFIER);
if(signerUid != null) if(signerUid != null)
mSignerUid.setText(signerUid); mSignerUid.setText(signerUid);
else else
mSignerUid.setText(R.string.unknown_uid); mSignerUid.setText(R.string.unknown_uid);
byte[] sigData = data.getBlob(7); byte[] sigData = data.getBlob(INDEX_KEY_DATA);
PGPSignature sig = PgpConversionHelper.BytesToPGPSignature(sigData); PGPSignature sig = PgpConversionHelper.BytesToPGPSignature(sigData);
if(sig != null) { if(sig != null) {
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(sig.getKeyAlgorithm(), 0); String algorithmStr = PgpKeyHelper.getAlgorithmInfo(sig.getKeyAlgorithm(), 0);

View File

@ -198,22 +198,26 @@ public class ViewKeyMainFragment extends Fragment implements
static final int KEYRING_INDEX_MASTER_KEY_ID = 1; static final int KEYRING_INDEX_MASTER_KEY_ID = 1;
static final int KEYRING_INDEX_USER_ID = 2; static final int KEYRING_INDEX_USER_ID = 2;
static final String[] USER_IDS_PROJECTION = static final String[] USER_IDS_PROJECTION = new String[]{
new String[]{ KeychainContract.UserIds._ID,
KeychainContract.UserIds._ID, KeychainContract.UserIds.USER_ID,
KeychainContract.UserIds.USER_ID, KeychainContract.UserIds.RANK,
KeychainContract.UserIds.RANK, "verified",
}; };
// not the main user id
static final String USER_IDS_SELECTION =
KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.RANK + " > 0 ";
static final String USER_IDS_SORT_ORDER = static final String USER_IDS_SORT_ORDER =
KeychainContract.UserIds.RANK + " COLLATE LOCALIZED ASC"; KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.RANK + " COLLATE LOCALIZED ASC";
static final String[] KEYS_PROJECTION = static final String[] KEYS_PROJECTION = new String[]{
new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID, KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM, KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM,
KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY, KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY,
KeychainContract.Keys.CAN_SIGN, KeychainContract.Keys.CAN_ENCRYPT, KeychainContract.Keys.CAN_SIGN, KeychainContract.Keys.CAN_ENCRYPT,
KeychainContract.Keys.CREATION, KeychainContract.Keys.EXPIRY, KeychainContract.Keys.CREATION, KeychainContract.Keys.EXPIRY,
KeychainContract.Keys.FINGERPRINT}; KeychainContract.Keys.FINGERPRINT
};
static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC"; static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC";
static final int KEYS_INDEX_ID = 0; static final int KEYS_INDEX_ID = 0;
static final int KEYS_INDEX_KEY_ID = 1; static final int KEYS_INDEX_KEY_ID = 1;

View File

@ -60,24 +60,6 @@
android:paddingRight="5dip" /> android:paddingRight="5dip" />
</TableRow> </TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingRight="10dip"
android:text="@string/label_subkey_rank" />
<TextView
android:id="@+id/subkey_rank"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingRight="5dip" />
</TableRow>
<TableRow <TableRow
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent"> android:layout_height="fill_parent">