extract database access from CachedPublicKeyRing

This commit is contained in:
Vincent Breitmoser
2018-06-26 10:24:19 +02:00
parent aa640f3227
commit 31830a8c86
40 changed files with 328 additions and 730 deletions

View File

@@ -24,24 +24,21 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.os.CancellationSignal;
import android.text.TextUtils;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
@@ -56,14 +53,13 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Numeric9x4PassphraseUtil;
import org.sufficientlysecure.keychain.util.CountingOutputStream;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Numeric9x4PassphraseUtil;
import org.sufficientlysecure.keychain.util.Passphrase;
import timber.log.Timber;
@@ -84,8 +80,6 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
KeyRings.MASTER_KEY_ID,
KeyRings.HAS_ANY_SECRET
};
private static final int INDEX_MASTER_KEY_ID = 0;
private static final int INDEX_HAS_ANY_SECRET = 1;
// this is a very simple matcher, we only need basic sanitization
private static final Pattern HEADER_PATTERN = Pattern.compile("[a-zA-Z0-9_-]+: [^\\n]+");
@@ -224,42 +218,36 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
OutputStream outStream, List<String> extraSecretKeyHeaders) {
// noinspection unused TODO use these in a log entry
int okSecret = 0, okPublic = 0;
int progress = 0;
Cursor cursor = queryForKeys(masterKeyIds);
if (cursor == null || !cursor.moveToFirst()) {
log.add(LogType.MSG_BACKUP_ERROR_DB, 1);
return false; // new ExportResult(ExportResult.RESULT_ERROR, log);
}
try {
int numKeys = cursor.getCount();
List<UnifiedKeyInfo> unifiedKeyInfos;
if (masterKeyIds == null) {
unifiedKeyInfos = mKeyRepository.getAllUnifiedKeyInfo();
} else {
unifiedKeyInfos = mKeyRepository.getUnifiedKeyInfo(masterKeyIds);
}
int numKeys = unifiedKeyInfos.size();
updateProgress(mContext.getResources().getQuantityString(R.plurals.progress_exporting_key, numKeys),
0, numKeys);
// For each public masterKey id
while (!cursor.isAfterLast()) {
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
log.add(LogType.MSG_BACKUP_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(masterKeyId));
for (UnifiedKeyInfo keyInfo : unifiedKeyInfos) {
log.add(LogType.MSG_BACKUP_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyInfo.master_key_id()));
boolean publicKeyWriteOk = false;
if (exportPublic) {
publicKeyWriteOk = writePublicKeyToStream(masterKeyId, log, outStream);
publicKeyWriteOk = writePublicKeyToStream(keyInfo.master_key_id(), log, outStream);
if (publicKeyWriteOk) {
okPublic += 1;
}
}
if (publicKeyWriteOk || !exportPublic) {
boolean hasSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) > 0;
if (exportSecret && hasSecret) {
log.add(LogType.MSG_BACKUP_SECRET, 2, KeyFormattingUtils.beautifyKeyId(masterKeyId));
if (writeSecretKeyToStream(masterKeyId, log, outStream, extraSecretKeyHeaders)) {
if (exportSecret && keyInfo.has_any_secret()) {
log.add(LogType.MSG_BACKUP_SECRET, 2, KeyFormattingUtils.beautifyKeyId(keyInfo.master_key_id()));
if (writeSecretKeyToStream(keyInfo.master_key_id(), log, outStream, extraSecretKeyHeaders)) {
okSecret += 1;
}
extraSecretKeyHeaders = null;
@@ -267,7 +255,6 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
}
updateProgress(progress++, numKeys);
cursor.moveToNext();
}
updateProgress(R.string.progress_done, numKeys, numKeys);
@@ -282,7 +269,6 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
} catch (Exception e) {
Timber.e(e, "error closing stream");
}
cursor.close();
}
return true;
@@ -342,29 +328,4 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
}
}
private Cursor queryForKeys(long[] masterKeyIds) {
String selection = null, selectionArgs[] = null;
if (masterKeyIds != null) {
// convert long[] to String[]
selectionArgs = new String[masterKeyIds.length];
for (int i = 0; i < masterKeyIds.length; i++) {
selectionArgs[i] = Long.toString(masterKeyIds[i]);
}
// generates ?,?,? as placeholders for selectionArgs
String placeholders = TextUtils.join(",",
Collections.nCopies(masterKeyIds.length, "?"));
// put together selection string
selection = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
+ " IN (" + placeholders + ")";
}
return mKeyRepository.getContentResolver().query(
KeyRings.buildUnifiedKeyRingsUri(), PROJECTION, selection, selectionArgs,
Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
);
}
}

View File

@@ -86,10 +86,8 @@ public class CertifyOperation extends BaseReadWriteOperation<CertifyActionsParce
log.add(LogType.MSG_CRT_MASTER_FETCH, 1);
CachedPublicKeyRing cachedPublicKeyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId);
Passphrase passphrase;
switch (cachedPublicKeyRing.getSecretKeyType(masterKeyId)) {
switch (mKeyRepository.getSecretKeyType(masterKeyId)) {
case PASSPHRASE:
passphrase = cryptoInput.getPassphrase();
if (passphrase == null) {

View File

@@ -21,12 +21,11 @@ package org.sufficientlysecure.keychain.operations;
import android.content.Context;
import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.RevokeResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.RevokeKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
@@ -56,18 +55,21 @@ public class RevokeOperation extends BaseReadWriteOperation<RevokeKeyringParcel>
KeyFormattingUtils.beautifyKeyId(masterKeyId));
try {
CachedPublicKeyRing keyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId);
UnifiedKeyInfo keyInfo = mKeyRepository.getUnifiedKeyInfo(masterKeyId);
if (keyInfo == null) {
log.add(OperationResult.LogType.MSG_REVOKE_ERROR_KEY_FAIL, 1);
return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId);
}
// check if this is a master secret key we can work with
switch (keyRing.getSecretKeyType(masterKeyId)) {
switch (mKeyRepository.getSecretKeyType(masterKeyId)) {
case GNU_DUMMY:
log.add(OperationResult.LogType.MSG_EK_ERROR_DUMMY, 1);
return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId);
}
SaveKeyringParcel.Builder saveKeyringParcel =
SaveKeyringParcel.buildChangeKeyringParcel(masterKeyId, keyRing.getFingerprint());
SaveKeyringParcel.buildChangeKeyringParcel(masterKeyId, keyInfo.fingerprint());
// all revoke operations are made atomic as of now
saveKeyringParcel.setUpdateOptions(revokeKeyringParcel.isShouldUpload(), true,
@@ -93,7 +95,7 @@ public class RevokeOperation extends BaseReadWriteOperation<RevokeKeyringParcel>
return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId);
}
} catch (PgpKeyNotFoundException | KeyWritableRepository.NotFoundException e) {
} catch (KeyWritableRepository.NotFoundException e) {
Timber.e(e, "could not find key to revoke");
log.add(OperationResult.LogType.MSG_REVOKE_ERROR_KEY_FAIL, 1);
return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId);

View File

@@ -124,7 +124,7 @@ public class OpenPgpSignatureResultBuilder {
} catch (PgpKeyNotFoundException e) {
Timber.d("No primary user id in keyring with master key id " + signingRing.getMasterKeyId());
}
setSignatureKeyCertified(signingRing.getVerified() != VerificationStatus.UNVERIFIED);
setSignatureKeyCertified(signingRing.getVerified() == VerificationStatus.VERIFIED_SECRET);
List<String> allUserIds = signingRing.getUnorderedUserIds();
List<String> confirmedUserIds = mKeyRepository.getConfirmedUserIds(signingRing.getMasterKeyId());

View File

@@ -71,7 +71,6 @@ import org.sufficientlysecure.keychain.pgp.SecurityProblem.EncryptionAlgorithmPr
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.MissingMdc;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -633,7 +632,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
break;
}
CachedPublicKeyRing cachedPublicKeyRing;
try {
// get actual keyring object based on master key id
Long masterKeyId = mKeyRepository.getMasterKeyIdBySubkeyId(subKeyId);
@@ -641,7 +639,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1);
continue;
}
cachedPublicKeyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId);
// allow only specific keys for decryption?
if (input.getAllowedKeyIds() != null) {
@@ -658,7 +655,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
}
SecretKeyType secretKeyType = cachedPublicKeyRing.getSecretKeyType(subKeyId);
SecretKeyType secretKeyType = mKeyRepository.getSecretKeyType(subKeyId);
if (!secretKeyType.isUsable()) {
decryptionKey = null;
log.add(LogType.MSG_DC_ASKIP_UNAVAILABLE, indent + 1);

View File

@@ -63,10 +63,9 @@ import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainComp
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainHashAlgorithmTags;
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@@ -226,8 +225,8 @@ public class PgpSignEncryptOperation extends BaseOperation<PgpSignEncryptInputPa
Long signingSubKeyId = data.getSignatureSubKeyId();
if (signingSubKeyId == null) {
try {
signingSubKeyId = mKeyRepository.getCachedPublicKeyRing(signingMasterKeyId).getSecretSignId();
} catch (PgpKeyNotFoundException e) {
signingSubKeyId = mKeyRepository.getSecretSignId(signingMasterKeyId);
} catch (NotFoundException e) {
log.add(LogType.MSG_PSE_ERROR_KEY_SIGN, indent);
return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
}
@@ -257,7 +256,7 @@ public class PgpSignEncryptOperation extends BaseOperation<PgpSignEncryptInputPa
return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
}
switch (mKeyRepository.getCachedPublicKeyRing(signingMasterKeyId).getSecretKeyType(signingSubKeyId)) {
switch (mKeyRepository.getSecretKeyType(signingSubKeyId)) {
case DIVERT_TO_CARD:
case PASSPHRASE_EMPTY: {
if (!signingKey.unlock(new Passphrase())) {

View File

@@ -41,6 +41,15 @@ class AbstractDao {
return result;
}
<T> T mapSingleRow(SupportSQLiteQuery query, Mapper<T> mapper) {
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToNext()) {
return mapper.map(cursor);
}
}
return null;
}
interface Mapper<T> {
T map(Cursor cursor);
}

View File

@@ -18,16 +18,11 @@
package org.sufficientlysecure.keychain.provider;
import android.net.Uri;
import org.sufficientlysecure.keychain.model.CustomColumnAdapters;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import timber.log.Timber;
/** This implementation of KeyRing provides a cached view of PublicKeyRing
@@ -47,234 +42,64 @@ import timber.log.Timber;
*
*/
public class CachedPublicKeyRing extends KeyRing {
private UnifiedKeyInfo unifiedKeyInfo;
final KeyRepository mKeyRepository;
final Uri mUri;
public CachedPublicKeyRing(KeyRepository keyRepository, Uri uri) {
mKeyRepository = keyRepository;
mUri = uri;
public CachedPublicKeyRing(UnifiedKeyInfo unifiedKeyInfo) {
this.unifiedKeyInfo = unifiedKeyInfo;
}
@Override
public long getMasterKeyId() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeychainContract.KeyRings.MASTER_KEY_ID, KeyRepository.FIELD_TYPE_INTEGER);
return (Long) data;
} catch (KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
public long getMasterKeyId() {
return unifiedKeyInfo.master_key_id();
}
/**
* 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 long extractOrGetMasterKeyId() throws PgpKeyNotFoundException {
// try extracting from the uri first
String firstSegment = mUri.getPathSegments().get(1);
if (!"find".equals(firstSegment)) try {
return Long.parseLong(firstSegment);
} catch (NumberFormatException e) {
// didn't work? oh well.
Timber.d("Couldn't get masterKeyId from URI, querying...");
}
return getMasterKeyId();
public byte[] getFingerprint() {
return unifiedKeyInfo.fingerprint();
}
public byte[] getFingerprint() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeychainContract.KeyRings.FINGERPRINT, KeyRepository.FIELD_TYPE_BLOB);
return (byte[]) data;
} catch (KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
}
public long getCreationTime() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeychainContract.KeyRings.CREATION, KeyRepository.FIELD_TYPE_INTEGER);
return (long) data;
} catch (KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
public long getCreationTime() {
return unifiedKeyInfo.creation();
}
@Override
public String getPrimaryUserId() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeychainContract.KeyRings.USER_ID,
KeyRepository.FIELD_TYPE_STRING);
return (String) data;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
public String getPrimaryUserId() {
return unifiedKeyInfo.user_id();
}
public String getPrimaryUserIdWithFallback() throws PgpKeyNotFoundException {
public String getPrimaryUserIdWithFallback() {
return getPrimaryUserId();
}
public String getName() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeyRings.NAME,
KeyRepository.FIELD_TYPE_STRING);
return (String) data;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
}
public String getEmail() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeyRings.EMAIL,
KeyRepository.FIELD_TYPE_STRING);
return (String) data;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
}
public String getComment() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeyRings.COMMENT,
KeyRepository.FIELD_TYPE_STRING);
return (String) data;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
@Override
public boolean isRevoked() {
return unifiedKeyInfo.is_revoked();
}
@Override
public boolean isRevoked() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeychainContract.KeyRings.IS_REVOKED,
KeyRepository.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
public boolean canCertify() {
return unifiedKeyInfo.can_certify();
}
@Override
public boolean canCertify() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeychainContract.KeyRings.HAS_CERTIFY_SECRET,
KeyRepository.FIELD_TYPE_NULL);
return !((Boolean) data);
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
public long getEncryptId() {
return unifiedKeyInfo.has_encrypt_key_int();
}
@Override
public long getEncryptId() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeyRings.HAS_ENCRYPT,
KeyRepository.FIELD_TYPE_INTEGER);
return (Long) data;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
public boolean hasEncrypt() {
return unifiedKeyInfo.has_encrypt_key();
}
public long getAuthenticationId() {
return unifiedKeyInfo.has_auth_key_int();
}
@Override
public boolean hasEncrypt() throws PgpKeyNotFoundException {
return getEncryptId() != 0;
public VerificationStatus getVerified() {
return unifiedKeyInfo.verified();
}
/** Returns the key id which should be used for signing.
*
* This method returns keys which are actually available (ie. secret available, and not stripped,
* revoked, or expired), hence only works on keyrings where a secret key is available!
*
*/
public long getSecretSignId() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeyRings.HAS_SIGN_SECRET,
KeyRepository.FIELD_TYPE_INTEGER);
return (Long) data;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
}
/** Returns the key id which should be used for authentication.
*
* This method returns keys which are actually available (ie. secret available, and not stripped,
* revoked, or expired), hence only works on keyrings where a secret key is available!
*
*/
public long getSecretAuthenticationId() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeyRings.HAS_AUTHENTICATE_SECRET,
KeyRepository.FIELD_TYPE_INTEGER);
return (Long) data;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
}
public long getAuthenticationId() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeyRings.HAS_AUTHENTICATE,
KeyRepository.FIELD_TYPE_INTEGER);
return (Long) data;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
}
@Override
public VerificationStatus getVerified() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeychainContract.KeyRings.VERIFIED,
KeyRepository.FIELD_TYPE_INTEGER);
return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode((Long) data);
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
}
public boolean hasAnySecret() throws PgpKeyNotFoundException {
try {
Object data = mKeyRepository.getGenericData(mUri,
KeychainContract.KeyRings.HAS_ANY_SECRET,
KeyRepository.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
}
public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException {
SecretKeyType secretKeyType = mKeyRepository.getSecretKeyType(keyId);
if (secretKeyType == null) {
throw new NotFoundException();
}
return secretKeyType;
}
public byte[] getEncoded() throws PgpKeyNotFoundException {
try {
return mKeyRepository.loadPublicKeyRingData(getMasterKeyId());
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
}
public boolean hasAnySecret() {
return unifiedKeyInfo.has_any_secret();
}
}

View File

@@ -21,13 +21,11 @@ package org.sufficientlysecure.keychain.provider;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import com.squareup.sqldelight.SqlDelightQuery;
import org.bouncycastle.bcpg.ArmoredOutputStream;
@@ -43,21 +41,10 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStat
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import timber.log.Timber;
public class KeyRepository extends AbstractDao {
// If we ever switch to api level 11, we can ditch this whole mess!
public static final int FIELD_TYPE_NULL = 1;
// this is called integer to stay coherent with the constants in Cursor (api level 11)
public static final int FIELD_TYPE_INTEGER = 2;
public static final int FIELD_TYPE_FLOAT = 3;
public static final int FIELD_TYPE_STRING = 4;
public static final int FIELD_TYPE_BLOB = 5;
final ContentResolver contentResolver;
final LocalPublicKeyStorage mLocalPublicKeyStorage;
final LocalSecretKeyStorage localSecretKeyStorage;
@@ -115,72 +102,13 @@ public class KeyRepository extends AbstractDao {
mLog = new OperationLog();
}
Object getGenericData(Uri uri, String column, int type) throws NotFoundException {
Object result = getGenericData(uri, new String[]{column}, new int[]{type}, null).get(column);
if (result == null) {
// replace with getUnifiedKeyInfo
public CachedPublicKeyRing getCachedPublicKeyRing(long masterKeyId) throws NotFoundException {
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
if (unifiedKeyInfo == null) {
throw new NotFoundException();
}
return result;
}
private HashMap<String, Object> getGenericData(Uri uri, String[] proj, int[] types)
throws NotFoundException {
return getGenericData(uri, proj, types, null);
}
private HashMap<String, Object> getGenericData(Uri uri, String[] proj, int[] types, String selection)
throws NotFoundException {
Cursor cursor = contentResolver.query(uri, proj, selection, null, null);
try {
HashMap<String, Object> result = new HashMap<>(proj.length);
if (cursor != null && cursor.moveToFirst()) {
int pos = 0;
for (String p : proj) {
switch (types[pos]) {
case FIELD_TYPE_NULL:
result.put(p, cursor.isNull(pos));
break;
case FIELD_TYPE_INTEGER:
result.put(p, cursor.getLong(pos));
break;
case FIELD_TYPE_FLOAT:
result.put(p, cursor.getFloat(pos));
break;
case FIELD_TYPE_STRING:
result.put(p, cursor.getString(pos));
break;
case FIELD_TYPE_BLOB:
result.put(p, cursor.getBlob(pos));
break;
}
pos += 1;
}
} else {
// If no data was found, throw an appropriate exception
throw new NotFoundException();
}
return result;
} finally {
if (cursor != null) {
cursor.close();
}
}
}
public HashMap<String, Object> getUnifiedData(long masterKeyId, String[] proj, int[] types)
throws NotFoundException {
return getGenericData(KeyRings.buildUnifiedKeyRingUri(masterKeyId), proj, types);
}
public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws PgpKeyNotFoundException {
long masterKeyId = new CachedPublicKeyRing(this, queryUri).extractOrGetMasterKeyId();
return getCachedPublicKeyRing(masterKeyId);
}
public CachedPublicKeyRing getCachedPublicKeyRing(long id) {
return new CachedPublicKeyRing(this, KeyRings.buildUnifiedKeyRingUri(id));
return new CachedPublicKeyRing(unifiedKeyInfo);
}
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId) throws NotFoundException {
@@ -211,11 +139,7 @@ public class KeyRepository extends AbstractDao {
}
public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) {
long[] signerKeyIds = new long[signerMasterKeyIds.size()];
int i = 0;
for (Long signerKeyId : signerMasterKeyIds) {
signerKeyIds[i++] = signerKeyId;
}
long[] signerKeyIds = getLongListAsArray(signerMasterKeyIds);
SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds);
return mapAllRows(query, KeyRingPublic.FACTORY.selectAllMasterKeyIdsMapper()::map);
}
@@ -240,6 +164,11 @@ public class KeyRepository extends AbstractDao {
}
}
public List<UnifiedKeyInfo> getUnifiedKeyInfo(long... masterKeyIds) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyIds(masterKeyIds);
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
}
public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%');
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
@@ -275,17 +204,17 @@ public class KeyRepository extends AbstractDao {
return mapAllRows(query, SubKey.SUBKEY_MAPPER::map);
}
public SecretKeyType getSecretKeyType(long keyId) {
public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectSecretKeyType(keyId);
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToFirst()) {
return SubKey.SKT_MAPPER.map(cursor);
}
return null;
throw new NotFoundException();
}
}
private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException, PgpGeneralException {
private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = new ArmoredOutputStream(bos);
@@ -295,15 +224,13 @@ public class KeyRepository extends AbstractDao {
return bos.toByteArray();
}
public String getPublicKeyRingAsArmoredString(long masterKeyId)
throws NotFoundException, IOException, PgpGeneralException {
public String getPublicKeyRingAsArmoredString(long masterKeyId) throws NotFoundException, IOException {
byte[] data = loadPublicKeyRingData(masterKeyId);
byte[] armoredData = getKeyRingAsArmoredData(data);
return new String(armoredData);
}
public byte[] getSecretKeyRingAsArmoredData(long masterKeyId)
throws NotFoundException, IOException, PgpGeneralException {
public byte[] getSecretKeyRingAsArmoredData(long masterKeyId) throws NotFoundException, IOException {
byte[] data = loadSecretKeyRingData(masterKeyId);
return getKeyRingAsArmoredData(data);
}
@@ -338,6 +265,24 @@ public class KeyRepository extends AbstractDao {
}
}
public long getSecretSignId(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId);
Long signKeyId = mapSingleRow(query, SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyIdMapper()::map);
if (signKeyId == null) {
throw new NotFoundException();
}
return signKeyId;
}
public Long getSecretAuthenticationId(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId);
Long authKeyId = mapSingleRow(query, SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyIdMapper()::map);
if (authKeyId == null) {
throw new NotFoundException();
}
return authKeyId;
}
public static class NotFoundException extends Exception {
public NotFoundException() {
}
@@ -346,4 +291,13 @@ public class KeyRepository extends AbstractDao {
super(name);
}
}
private long[] getLongListAsArray(List<Long> longList) {
long[] longs = new long[longList.size()];
int i = 0;
for (Long aLong : longList) {
longs[i++] = aLong;
}
return longs;
}
}

View File

@@ -29,7 +29,6 @@ import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
import android.support.annotation.NonNull;
@@ -40,6 +39,7 @@ import org.openintents.openpgp.util.OpenPgpUtils;
import org.sufficientlysecure.keychain.KeyRingsPublicModel.DeleteByMasterKeyId;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.CustomColumnAdapters;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
@@ -60,7 +60,6 @@ import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeySignatures;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
@@ -99,8 +98,7 @@ public class KeyWritableRepository extends KeyRepository {
localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, autocryptPeerDao);
}
@VisibleForTesting
KeyWritableRepository(Context context,
private KeyWritableRepository(Context context,
KeychainDatabase database, LocalPublicKeyStorage localPublicKeyStorage,
LocalSecretKeyStorage localSecretKeyStorage,
DatabaseNotifyManager databaseNotifyManager, AutocryptPeerDao autocryptPeerDao) {
@@ -120,40 +118,22 @@ public class KeyWritableRepository extends KeyRepository {
}
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
Cursor cursor = contentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] {
KeyRings.MASTER_KEY_ID,
// we pick from cache only information that is not easily available from keyrings
KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED
}, KeyRings.HAS_ANY_SECRET + " = 1", null, null);
LongSparseArray<CanonicalizedPublicKey> result = new LongSparseArray<>();
try {
LongSparseArray<CanonicalizedPublicKey> result = new LongSparseArray<>();
if (cursor == null) {
return result;
}
while (cursor.moveToNext()) {
try {
long masterKeyId = cursor.getLong(0);
long verified = cursor.getLong(2);
byte[] blob = loadPublicKeyRingData(masterKeyId);
VerificationStatus verificationStatus = CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(verified);
if (blob != null) {
result.put(masterKeyId, new CanonicalizedPublicKeyRing(blob, verificationStatus).getPublicKey());
}
} catch (NotFoundException e) {
throw new IllegalStateException("Error reading secret key data, this should not happen!", e);
List<UnifiedKeyInfo> unifiedKeyInfoWithSecret = getAllUnifiedKeyInfoWithSecret();
for (UnifiedKeyInfo unifiedKeyInfo : unifiedKeyInfoWithSecret) {
try {
byte[] blob = loadPublicKeyRingData(unifiedKeyInfo.master_key_id());
if (blob != null) {
result.put(unifiedKeyInfo.master_key_id(),
new CanonicalizedPublicKeyRing(blob, unifiedKeyInfo.verified()).getPublicKey());
}
}
return result;
} finally {
if (cursor != null) {
cursor.close();
} catch (NotFoundException e) {
throw new IllegalStateException("Error reading secret key data, this should not happen!", e);
}
}
return result;
}
// bits, in order: CESA. make SURE these are correct, we will get bad log entries otherwise!!

View File

@@ -99,9 +99,6 @@ public class KeychainContract {
public static final String PATH_UNIFIED = "unified";
public static final String PATH_FIND = "find";
public static final String PATH_BY_SUBKEY = "subkey";
public static final String PATH_PUBLIC = "public";
public static final String PATH_USER_IDS = "user_ids";
public static final String PATH_KEYS = "keys";
@@ -132,16 +129,6 @@ public class KeychainContract {
public static Uri buildGenericKeyRingUri(long masterKeyId) {
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).build();
}
public static Uri buildUnifiedKeyRingUri(long masterKeyId) {
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId))
.appendPath(PATH_UNIFIED).build();
}
public static Uri buildUnifiedKeyRingsFindBySubkeyUri(long subkey) {
return CONTENT_URI.buildUpon().appendPath(PATH_FIND)
.appendPath(PATH_BY_SUBKEY).appendPath(Long.toString(subkey)).build();
}
}
public static class KeyRingData implements KeyRingsColumns, BaseColumns {

View File

@@ -32,7 +32,9 @@ import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteException;
import android.support.annotation.VisibleForTesting;
import org.sufficientlysecure.keychain.ApiAllowedKeysModel;
import org.sufficientlysecure.keychain.ApiAppsModel;
import org.sufficientlysecure.keychain.AutocryptPeersModel;
import org.sufficientlysecure.keychain.CertsModel;
@@ -66,12 +68,15 @@ public class KeychainDatabase {
private static KeychainDatabase sInstance;
public static KeychainDatabase getInstance(Context context) {
if (sInstance == null) {
sInstance = new KeychainDatabase(context.getApplicationContext());
}
return sInstance;
}
@VisibleForTesting
public static void resetSingleton() {
sInstance = null;
}
public interface Tables {
String KEY_RINGS_PUBLIC = "keyrings_public";
String KEYS = "keys";
@@ -133,7 +138,7 @@ public class KeychainDatabase {
db.execSQL(ApiAppsModel.CREATE_TABLE);
db.execSQL(OverriddenWarningsModel.CREATE_TABLE);
db.execSQL(AutocryptPeersModel.CREATE_TABLE);
db.execSQL(ApiAppsModel.CREATE_TABLE);
db.execSQL(ApiAllowedKeysModel.CREATE_TABLE);
db.execSQL(KeysModel.UNIFIEDKEYVIEW);
db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysColumns.RANK + ", " + KeysColumns.MASTER_KEY_ID + ");");
@@ -460,8 +465,8 @@ public class KeychainDatabase {
// DANGEROUS, use in test code ONLY!
public void clearDatabase() {
getWritableDatabase().execSQL("delete from " + Tables.KEY_RINGS_PUBLIC);
getWritableDatabase().execSQL("delete from " + Tables.API_ALLOWED_KEYS);
getWritableDatabase().execSQL("delete from " + KeyRingsPublicModel.TABLE_NAME);
getWritableDatabase().execSQL("delete from " + ApiAllowedKeysModel.TABLE_NAME);
getWritableDatabase().execSQL("delete from api_apps");
}

View File

@@ -61,8 +61,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
private static final int KEY_RING_PUBLIC = 203;
private static final int KEY_RING_CERTS = 205;
private static final int KEY_RINGS_FIND_BY_SUBKEY = 401;
private static final int KEY_SIGNATURES = 700;
protected UriMatcher mUriMatcher;
@@ -88,16 +86,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
+ "/" + KeychainContract.PATH_UNIFIED,
KEY_RINGS_UNIFIED);
/*
* find by criteria other than master key id
*
* key_rings/find/subkey/_
*
*/
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_SUBKEY + "/*",
KEY_RINGS_FIND_BY_SUBKEY);
/*
* list key_ring specifics
*
@@ -174,8 +162,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
switch (match) {
case KEY_RING_UNIFIED:
case KEY_RINGS_UNIFIED:
case KEY_RINGS_FIND_BY_SUBKEY: {
case KEY_RINGS_UNIFIED: {
HashMap<String, String> projectionMap = new HashMap<>();
projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id");
projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
@@ -318,28 +305,8 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
// in case there are multiple verifying certificates
groupBy = Tables.KEYS + "." + Keys.MASTER_KEY_ID;
switch(match) {
case KEY_RING_UNIFIED: {
qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
break;
}
case KEY_RINGS_FIND_BY_SUBKEY: {
try {
String subkey = Long.valueOf(uri.getLastPathSegment()).toString();
qb.appendWhere(" AND EXISTS ("
+ " SELECT 1 FROM " + Tables.KEYS + " AS tmp"
+ " WHERE tmp." + UserPackets.MASTER_KEY_ID
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ " AND tmp." + Keys.KEY_ID + " = " + subkey + ""
+ ")");
} catch(NumberFormatException e) {
Timber.e(e, "Malformed find by subkey query!");
qb.appendWhere(" AND 0");
}
break;
}
}
qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
if (TextUtils.isEmpty(sortOrder)) {
sortOrder = Tables.USER_PACKETS + "." + UserPackets.USER_ID + " ASC";

View File

@@ -66,12 +66,11 @@ import org.sufficientlysecure.keychain.pgp.PgpSignEncryptData;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.SecurityProblem;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.ApiAppDao;
import org.sufficientlysecure.keychain.provider.AutocryptPeerDao;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus;
import org.sufficientlysecure.keychain.provider.OverriddenWarningsRepository;
import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResult;
@@ -139,9 +138,9 @@ public class OpenPgpService extends Service {
// get first usable subkey capable of signing
try {
long signSubKeyId = mKeyRepository.getCachedPublicKeyRing(signKeyId).getSecretSignId();
long signSubKeyId = mKeyRepository.getSecretSignId(signKeyId);
pgpData.setSignatureSubKeyId(signSubKeyId);
} catch (PgpKeyNotFoundException e) {
} catch (NotFoundException e) {
throw new Exception("signing subkey not found!", e);
}
}
@@ -230,7 +229,7 @@ public class OpenPgpService extends Service {
if (signKeyId == Constants.key.none) {
throw new Exception("No signing key given");
}
long signSubKeyId = mKeyRepository.getCachedPublicKeyRing(signKeyId).getSecretSignId();
long signSubKeyId = mKeyRepository.getSecretSignId(signKeyId);
pgpData.setSignatureMasterKeyId(signKeyId)
.setSignatureSubKeyId(signSubKeyId)
@@ -627,7 +626,8 @@ public class OpenPgpService extends Service {
}
try {
CanonicalizedPublicKeyRing keyRing = mKeyRepository.getCanonicalizedPublicKeyRing(masterKeyId);
CanonicalizedPublicKeyRing keyRing =
mKeyRepository.getCanonicalizedPublicKeyRing(masterKeyId);
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
@@ -749,7 +749,7 @@ public class OpenPgpService extends Service {
result.putExtra(OpenPgpApi.RESULT_PRIMARY_USER_ID, userId);
result.putExtra(OpenPgpApi.RESULT_KEY_CREATION_TIME, creationTime);
} catch (PgpKeyNotFoundException e) {
} catch (NotFoundException e) {
Timber.e(e, "Error loading key info");
return createErrorResultIntent(OpenPgpError.GENERIC_ERROR, e.getMessage());
}

View File

@@ -48,6 +48,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.ApiAppDao;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ssh.AuthenticationData;
@@ -59,8 +60,6 @@ import timber.log.Timber;
public class SshAuthenticationService extends Service {
private static final String TAG = "SshAuthService";
private ApiPermissionHelper mApiPermissionHelper;
private KeyRepository mKeyRepository;
private ApiAppDao mApiAppDao;
@@ -144,23 +143,18 @@ public class SshAuthenticationService extends Service {
AuthenticationData.Builder authData = AuthenticationData.builder();
authData.setAuthenticationMasterKeyId(masterKeyId);
CachedPublicKeyRing cachedPublicKeyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId);
long authSubKeyId;
int authSubKeyAlgorithm;
String authSubKeyCurveOid = null;
try {
// get first usable subkey capable of authentication
authSubKeyId = cachedPublicKeyRing.getSecretAuthenticationId();
authSubKeyId = mKeyRepository.getSecretAuthenticationId(masterKeyId);
// needed for encoding the resulting signature
authSubKeyAlgorithm = getPublicKey(masterKeyId).getAlgorithm();
if (authSubKeyAlgorithm == PublicKeyAlgorithmTags.ECDSA) {
authSubKeyCurveOid = getPublicKey(masterKeyId).getCurveOid();
}
} catch (PgpKeyNotFoundException e) {
return createExceptionErrorResult(SshAuthenticationApiError.NO_AUTH_KEY,
"authentication key for master key id not found in keychain", e);
} catch (KeyRepository.NotFoundException e) {
} catch (NotFoundException e) {
return createExceptionErrorResult(SshAuthenticationApiError.NO_SUCH_KEY,
"Key for master key id not found", e);
}
@@ -272,7 +266,7 @@ public class SshAuthenticationService extends Service {
try {
description = getDescription(masterKeyId);
} catch (PgpKeyNotFoundException e) {
} catch (NotFoundException e) {
return createExceptionErrorResult(SshAuthenticationApiError.NO_SUCH_KEY,
"Could not create description", e);
}
@@ -372,8 +366,7 @@ public class SshAuthenticationService extends Service {
return new SshPublicKeyResponse(sshPublicKeyBlob).toIntent();
}
private CanonicalizedPublicKey getPublicKey(long masterKeyId)
throws PgpKeyNotFoundException, KeyRepository.NotFoundException {
private CanonicalizedPublicKey getPublicKey(long masterKeyId) throws NotFoundException {
KeyRepository keyRepository = KeyRepository.create(getApplicationContext());
long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId)
.getAuthenticationId();
@@ -381,11 +374,11 @@ public class SshAuthenticationService extends Service {
.getPublicKey(authSubKeyId);
}
private String getDescription(long masterKeyId) throws PgpKeyNotFoundException {
private String getDescription(long masterKeyId) throws NotFoundException {
CachedPublicKeyRing cachedPublicKeyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId);
String description = "";
long authSubKeyId = cachedPublicKeyRing.getSecretAuthenticationId();
long authSubKeyId = mKeyRepository.getSecretAuthenticationId(masterKeyId);
description += cachedPublicKeyRing.getPrimaryUserId();
description += " (" + Long.toHexString(authSubKeyId) + ")";

View File

@@ -123,7 +123,7 @@ class RequestKeyPermissionPresenter {
}
CachedPublicKeyRing cachedPublicKeyRing = keyRepository.getCachedPublicKeyRing(masterKeyId);
SecretKeyType secretKeyType = cachedPublicKeyRing.getSecretKeyType(candidateSubKeyId);
SecretKeyType secretKeyType = keyRepository.getSecretKeyType(candidateSubKeyId);
if (secretKeyType.isUsable()) {
return cachedPublicKeyRing;
}

View File

@@ -18,6 +18,8 @@
package org.sufficientlysecure.keychain.service;
import java.util.Date;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -41,14 +43,11 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Constants.NotificationIds;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences;
import timber.log.Timber;
import java.util.Date;
/**
* This service runs in its own process, but is available to all other processes as the main
* passphrase cache. Use the static methods addCachedPassphrase and getCachedPassphrase for
@@ -246,8 +245,8 @@ public class PassphraseCacheService extends Service {
+ masterKeyId + ", subKeyId " + subKeyId);
// get the type of key (from the database)
CachedPublicKeyRing keyRing = KeyRepository.create(this).getCachedPublicKeyRing(masterKeyId);
SecretKeyType keyType = keyRing.getSecretKeyType(subKeyId);
KeyRepository keyRepository = KeyRepository.create(this);
SecretKeyType keyType = keyRepository.getSecretKeyType(subKeyId);
switch (keyType) {
case PASSPHRASE_EMPTY:

View File

@@ -17,8 +17,12 @@
package org.sufficientlysecure.keychain.ssh;
import java.util.Collection;
import android.content.Context;
import android.support.annotation.NonNull;
import org.bouncycastle.openpgp.AuthenticationSignatureGenerator;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
@@ -29,15 +33,13 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.util.Passphrase;
import timber.log.Timber;
import java.util.Collection;
import static java.lang.String.format;
@@ -101,8 +103,8 @@ public class AuthenticationOperation extends BaseOperation<AuthenticationParcel>
Long authSubKeyId = data.getAuthenticationSubKeyId();
if (authSubKeyId == null) {
try { // Get the key id of the authentication key belonging to the master key id
authSubKeyId = mKeyRepository.getCachedPublicKeyRing(authMasterKeyId).getSecretAuthenticationId();
} catch (PgpKeyNotFoundException e) {
authSubKeyId = mKeyRepository.getSecretAuthenticationId(authMasterKeyId);
} catch (NotFoundException e) {
log.add(LogType.MSG_AUTH_ERROR_KEY_AUTH, indent);
return new AuthenticationResult(AuthenticationResult.RESULT_ERROR, log);
}
@@ -142,9 +144,7 @@ public class AuthenticationOperation extends BaseOperation<AuthenticationParcel>
CanonicalizedSecretKey.SecretKeyType secretKeyType;
try {
secretKeyType = mKeyRepository
.getCachedPublicKeyRing(authMasterKeyId)
.getSecretKeyType(authSubKeyId);
secretKeyType = mKeyRepository.getSecretKeyType(authSubKeyId);
} catch (KeyRepository.NotFoundException e) {
log.add(LogType.MSG_AUTH_ERROR_KEY_AUTH, indent);
return new AuthenticationResult(AuthenticationResult.RESULT_ERROR, log);

View File

@@ -36,9 +36,9 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -75,7 +75,7 @@ public class CertifyKeyFragment
if (key.canCertify()) {
mCertifyKeySpinner.setPreSelectedKeyId(certifyKeyId);
}
} catch (PgpKeyNotFoundException e) {
} catch (NotFoundException e) {
Timber.e(e, "certify certify check failed");
}
}

View File

@@ -48,9 +48,9 @@ import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.UploadResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
@@ -413,10 +413,10 @@ public class CreateKeyFinalFragment extends Fragment {
KeyRepository keyRepository = KeyRepository.create(getContext());
SaveKeyringParcel.Builder builder;
CachedPublicKeyRing key = keyRepository.getCachedPublicKeyRing(saveKeyResult.mMasterKeyId);
try {
CachedPublicKeyRing key = keyRepository.getCachedPublicKeyRing(saveKeyResult.mMasterKeyId);
builder = SaveKeyringParcel.buildChangeKeyringParcel(saveKeyResult.mMasterKeyId, key.getFingerprint());
} catch (PgpKeyNotFoundException e) {
} catch (NotFoundException e) {
Timber.e("Key that should be moved to Security Token not found in database!");
return;
}

View File

@@ -38,6 +38,7 @@ import android.widget.Spinner;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.RevokeResult;
@@ -86,35 +87,23 @@ public class DeleteKeyDialogActivity extends FragmentActivity {
if (mMasterKeyIds.length == 1 && mHasSecret) {
// if mMasterKeyIds.length == 0 we let the DeleteOperation respond
try {
KeyRepository keyRepository = KeyRepository.create(this);
HashMap<String, Object> data = keyRepository.getUnifiedData(
mMasterKeyIds[0], new String[]{
KeychainContract.KeyRings.NAME,
KeychainContract.KeyRings.IS_REVOKED
}, new int[]{
KeyRepository.FIELD_TYPE_STRING,
KeyRepository.FIELD_TYPE_INTEGER
}
);
String name;
name = (String) data.get(KeychainContract.KeyRings.NAME);
if (name == null) {
name = getString(R.string.user_id_no_name);
}
if ((long) data.get(KeychainContract.KeyRings.IS_REVOKED) > 0) {
showNormalDeleteDialog();
} else {
showRevokeDeleteDialog(name);
}
} catch (KeyRepository.NotFoundException e) {
Timber.e(e, "Secret key to delete not found at DeleteKeyDialogActivity for "
+ mMasterKeyIds[0]);
KeyRepository keyRepository = KeyRepository.create(this);
UnifiedKeyInfo keyInfo = keyRepository.getUnifiedKeyInfo(mMasterKeyIds[0]);
if (keyInfo == null) {
Timber.e("Secret key to delete not found at DeleteKeyDialogActivity for " + mMasterKeyIds[0]);
finish();
return;
}
String name = keyInfo.name();
if (name == null) {
name = getString(R.string.user_id_no_name);
}
if (keyInfo.is_revoked()) {
showNormalDeleteDialog();
} else {
showRevokeDeleteDialog(name);
}
} else {
showNormalDeleteDialog();
@@ -269,36 +258,26 @@ public class DeleteKeyDialogActivity extends FragmentActivity {
if (masterKeyIds.length == 1) {
long masterKeyId = masterKeyIds[0];
try {
HashMap<String, Object> data = KeyRepository.create(getContext())
.getUnifiedData(
masterKeyId, new String[]{
KeychainContract.KeyRings.NAME,
KeychainContract.KeyRings.HAS_ANY_SECRET
}, new int[]{
KeyRepository.FIELD_TYPE_STRING,
KeyRepository.FIELD_TYPE_INTEGER
}
);
String name;
name = (String) data.get(KeychainContract.KeyRings.NAME);
if (name == null) {
name = getString(R.string.user_id_no_name);
}
if (hasSecret) {
// show title only for secret key deletions,
// see http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior
builder.setTitle(getString(R.string.title_delete_secret_key, name));
mMainMessage.setText(getString(R.string.secret_key_deletion_confirmation, name));
} else {
mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name));
}
} catch (KeyRepository.NotFoundException e) {
KeyRepository keyRepository = KeyRepository.create(getContext());
UnifiedKeyInfo keyInfo = keyRepository.getUnifiedKeyInfo(masterKeyId);
if (keyInfo == null) {
dismiss();
return null;
}
String name = keyInfo.name();
if (name == null) {
name = getString(R.string.user_id_no_name);
}
if (keyInfo.has_any_secret()) {
// show title only for secret key deletions,
// see http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior
builder.setTitle(getString(R.string.title_delete_secret_key, name));
mMainMessage.setText(getString(R.string.secret_key_deletion_confirmation, name));
} else {
mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name));
}
} else {
mMainMessage.setText(R.string.key_deletion_confirmation_multi);
}

View File

@@ -32,7 +32,6 @@ import com.tokenautocomplete.TokenCompleteTextView.TokenListener;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
@@ -142,7 +141,7 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
if (keyring.hasAnySecret()) {
mSignKeySpinner.setPreSelectedKeyId(signatureKeyId);
}
} catch (PgpKeyNotFoundException e) {
} catch (NotFoundException e) {
Timber.e(e, "key not found for signing!");
Notify.create(getActivity(), getString(R.string.error_preselect_sign_key,
KeyFormattingUtils.beautifyKeyId(signatureKeyId)),

View File

@@ -61,7 +61,6 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
@@ -115,10 +114,9 @@ public class PassphraseDialogActivity extends FragmentActivity {
// handle empty passphrases by directly returning an empty crypto input parcel
try {
CachedPublicKeyRing pubRing =
KeyRepository.create(this).getCachedPublicKeyRing(requiredInput.getMasterKeyId());
KeyRepository keyRepository = KeyRepository.create(this);
// use empty passphrase for empty passphrase
if (pubRing.getSecretKeyType(requiredInput.getSubKeyId()) == SecretKeyType.PASSPHRASE_EMPTY) {
if (keyRepository.getSecretKeyType(requiredInput.getSubKeyId()) == SecretKeyType.PASSPHRASE_EMPTY) {
// also return passphrase back to activity
Intent returnIntent = new Intent();
cryptoInputParcel = cryptoInputParcel.withPassphrase(new Passphrase(""), requiredInput.getSubKeyId());
@@ -299,7 +297,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
userId = getString(R.string.user_id_no_name);
}
keyType = cachedPublicKeyRing.getSecretKeyType(subKeyId);
keyType = keyRepository.getSecretKeyType(subKeyId);
switch (keyType) {
case PASSPHRASE:
message = getString(R.string.passphrase_for, userId);
@@ -316,7 +314,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
throw new AssertionError("Unhandled SecretKeyType (should not happen)");
}
}
} catch (PgpKeyNotFoundException | KeyRepository.NotFoundException e) {
} catch (KeyRepository.NotFoundException e) {
alert.setTitle(R.string.title_key_not_found);
alert.setMessage(getString(R.string.key_not_found, mRequiredInput.getSubKeyId()));
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

View File

@@ -54,8 +54,8 @@ import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.Certification.CertDetails;
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
@@ -382,9 +382,8 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements OnB
byte[] fingerprint;
try {
fingerprint = KeyRepository.create(activity).getCachedPublicKeyRing(
masterKeyId).getFingerprint();
} catch (PgpKeyNotFoundException e) {
fingerprint = KeyRepository.create(activity).getCachedPublicKeyRing(masterKeyId).getFingerprint();
} catch (NotFoundException e) {
throw new IllegalStateException("Key to verify linked id for must exist in db!");
}

View File

@@ -483,8 +483,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements
private boolean keyHasPassphrase() {
try {
long masterKeyId = unifiedKeyInfo.master_key_id();
SecretKeyType secretKeyType =
keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretKeyType(masterKeyId);
SecretKeyType secretKeyType = keyRepository.getSecretKeyType(masterKeyId);
switch (secretKeyType) {
// all of these make no sense to ask
case PASSPHRASE_EMPTY:

View File

@@ -29,14 +29,12 @@ import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.content.AsyncTaskLoader;
import android.text.TextUtils;
import android.util.Log;
import com.google.auto.value.AutoValue;
import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.Request.Builder;
import okhttp3.Response;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient;
import org.sufficientlysecure.keychain.keyimport.KeyserverClient.QueryFailedException;
@@ -48,11 +46,8 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.Operat
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.token.PublicKeyRetrievalLoader.KeyRetrievalResult;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ParcelableProxy;
@@ -120,7 +115,6 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
log.add(LogType.MSG_RET_LOCAL_NOT_FOUND, 2);
continue;
}
CachedPublicKeyRing cachedPublicKeyRing = keyRepository.getCachedPublicKeyRing(masterKeyId);
// TODO check fingerprint
// if (!Arrays.equals(fingerprints, cachedPublicKeyRing.getFingerprint())) {
@@ -130,7 +124,7 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
// log.add(LogType.MSG_RET_LOCAL_FP_MATCH, 1);
// }
switch (cachedPublicKeyRing.getSecretKeyType(keyId)) {
switch (keyRepository.getSecretKeyType(keyId)) {
case PASSPHRASE:
case PASSPHRASE_EMPTY: {
log.add(LogType.MSG_RET_LOCAL_SECRET, 1);

View File

@@ -414,7 +414,7 @@ public class TransferPresenter implements KeyTransferCallback, LoaderCallbacks<L
byte[] armoredSecretKey = databaseInteractor.getSecretKeyRingAsArmoredData(masterKeyId);
secretKeyAdapter.focusItem(masterKeyId);
connectionSend(armoredSecretKey, Long.toString(masterKeyId));
} catch (IOException | NotFoundException | PgpGeneralException e) {
} catch (IOException | NotFoundException e) {
// TODO
e.printStackTrace();
}