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.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import android.content.Context; import android.content.Context;
import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.os.CancellationSignal; import android.support.v4.os.CancellationSignal;
import android.text.TextUtils;
import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; 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.ExportResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; 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;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.service.BackupKeyringParcel; import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Numeric9x4PassphraseUtil;
import org.sufficientlysecure.keychain.util.CountingOutputStream; import org.sufficientlysecure.keychain.util.CountingOutputStream;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Numeric9x4PassphraseUtil;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
import timber.log.Timber; import timber.log.Timber;
@@ -84,8 +80,6 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID,
KeyRings.HAS_ANY_SECRET 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 // this is a very simple matcher, we only need basic sanitization
private static final Pattern HEADER_PATTERN = Pattern.compile("[a-zA-Z0-9_-]+: [^\\n]+"); 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) { OutputStream outStream, List<String> extraSecretKeyHeaders) {
// noinspection unused TODO use these in a log entry // noinspection unused TODO use these in a log entry
int okSecret = 0, okPublic = 0; int okSecret = 0, okPublic = 0;
int progress = 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 { try {
List<UnifiedKeyInfo> unifiedKeyInfos;
int numKeys = cursor.getCount(); 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), updateProgress(mContext.getResources().getQuantityString(R.plurals.progress_exporting_key, numKeys),
0, numKeys); 0, numKeys);
// For each public masterKey id // For each public masterKey id
while (!cursor.isAfterLast()) { for (UnifiedKeyInfo keyInfo : unifiedKeyInfos) {
log.add(LogType.MSG_BACKUP_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyInfo.master_key_id()));
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
log.add(LogType.MSG_BACKUP_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(masterKeyId));
boolean publicKeyWriteOk = false; boolean publicKeyWriteOk = false;
if (exportPublic) { if (exportPublic) {
publicKeyWriteOk = writePublicKeyToStream(masterKeyId, log, outStream); publicKeyWriteOk = writePublicKeyToStream(keyInfo.master_key_id(), log, outStream);
if (publicKeyWriteOk) { if (publicKeyWriteOk) {
okPublic += 1; okPublic += 1;
} }
} }
if (publicKeyWriteOk || !exportPublic) { if (publicKeyWriteOk || !exportPublic) {
boolean hasSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) > 0; if (exportSecret && keyInfo.has_any_secret()) {
if (exportSecret && hasSecret) { log.add(LogType.MSG_BACKUP_SECRET, 2, KeyFormattingUtils.beautifyKeyId(keyInfo.master_key_id()));
log.add(LogType.MSG_BACKUP_SECRET, 2, KeyFormattingUtils.beautifyKeyId(masterKeyId)); if (writeSecretKeyToStream(keyInfo.master_key_id(), log, outStream, extraSecretKeyHeaders)) {
if (writeSecretKeyToStream(masterKeyId, log, outStream, extraSecretKeyHeaders)) {
okSecret += 1; okSecret += 1;
} }
extraSecretKeyHeaders = null; extraSecretKeyHeaders = null;
@@ -267,7 +255,6 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
} }
updateProgress(progress++, numKeys); updateProgress(progress++, numKeys);
cursor.moveToNext();
} }
updateProgress(R.string.progress_done, numKeys, numKeys); updateProgress(R.string.progress_done, numKeys, numKeys);
@@ -282,7 +269,6 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
} catch (Exception e) { } catch (Exception e) {
Timber.e(e, "error closing stream"); Timber.e(e, "error closing stream");
} }
cursor.close();
} }
return true; 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); log.add(LogType.MSG_CRT_MASTER_FETCH, 1);
CachedPublicKeyRing cachedPublicKeyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId);
Passphrase passphrase; Passphrase passphrase;
switch (mKeyRepository.getSecretKeyType(masterKeyId)) {
switch (cachedPublicKeyRing.getSecretKeyType(masterKeyId)) {
case PASSPHRASE: case PASSPHRASE:
passphrase = cryptoInput.getPassphrase(); passphrase = cryptoInput.getPassphrase();
if (passphrase == null) { if (passphrase == null) {

View File

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

View File

@@ -124,7 +124,7 @@ public class OpenPgpSignatureResultBuilder {
} catch (PgpKeyNotFoundException e) { } catch (PgpKeyNotFoundException e) {
Timber.d("No primary user id in keyring with master key id " + signingRing.getMasterKeyId()); 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> allUserIds = signingRing.getUnorderedUserIds();
List<String> confirmedUserIds = mKeyRepository.getConfirmedUserIds(signingRing.getMasterKeyId()); 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.KeySecurityProblem;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.MissingMdc; import org.sufficientlysecure.keychain.pgp.SecurityProblem.MissingMdc;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository; import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -633,7 +632,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
break; break;
} }
CachedPublicKeyRing cachedPublicKeyRing;
try { try {
// get actual keyring object based on master key id // get actual keyring object based on master key id
Long masterKeyId = mKeyRepository.getMasterKeyIdBySubkeyId(subKeyId); 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); log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1);
continue; continue;
} }
cachedPublicKeyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId);
// allow only specific keys for decryption? // allow only specific keys for decryption?
if (input.getAllowedKeyIds() != null) { 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()) { if (!secretKeyType.isUsable()) {
decryptionKey = null; decryptionKey = null;
log.add(LogType.MSG_DC_ASKIP_UNAVAILABLE, indent + 1); 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.OpenKeychainHashAlgorithmTags;
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags; import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; 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;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository; 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.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@@ -226,8 +225,8 @@ public class PgpSignEncryptOperation extends BaseOperation<PgpSignEncryptInputPa
Long signingSubKeyId = data.getSignatureSubKeyId(); Long signingSubKeyId = data.getSignatureSubKeyId();
if (signingSubKeyId == null) { if (signingSubKeyId == null) {
try { try {
signingSubKeyId = mKeyRepository.getCachedPublicKeyRing(signingMasterKeyId).getSecretSignId(); signingSubKeyId = mKeyRepository.getSecretSignId(signingMasterKeyId);
} catch (PgpKeyNotFoundException e) { } catch (NotFoundException e) {
log.add(LogType.MSG_PSE_ERROR_KEY_SIGN, indent); log.add(LogType.MSG_PSE_ERROR_KEY_SIGN, indent);
return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
} }
@@ -257,7 +256,7 @@ public class PgpSignEncryptOperation extends BaseOperation<PgpSignEncryptInputPa
return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
} }
switch (mKeyRepository.getCachedPublicKeyRing(signingMasterKeyId).getSecretKeyType(signingSubKeyId)) { switch (mKeyRepository.getSecretKeyType(signingSubKeyId)) {
case DIVERT_TO_CARD: case DIVERT_TO_CARD:
case PASSPHRASE_EMPTY: { case PASSPHRASE_EMPTY: {
if (!signingKey.unlock(new Passphrase())) { if (!signingKey.unlock(new Passphrase())) {

View File

@@ -41,6 +41,15 @@ class AbstractDao {
return result; 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> { interface Mapper<T> {
T map(Cursor cursor); T map(Cursor cursor);
} }

View File

@@ -18,16 +18,11 @@
package org.sufficientlysecure.keychain.provider; package org.sufficientlysecure.keychain.provider;
import android.net.Uri; import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.CustomColumnAdapters;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.KeyRing; 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.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import timber.log.Timber;
/** This implementation of KeyRing provides a cached view of PublicKeyRing /** This implementation of KeyRing provides a cached view of PublicKeyRing
@@ -47,234 +42,64 @@ import timber.log.Timber;
* *
*/ */
public class CachedPublicKeyRing extends KeyRing { public class CachedPublicKeyRing extends KeyRing {
private UnifiedKeyInfo unifiedKeyInfo;
final KeyRepository mKeyRepository; public CachedPublicKeyRing(UnifiedKeyInfo unifiedKeyInfo) {
final Uri mUri; this.unifiedKeyInfo = unifiedKeyInfo;
public CachedPublicKeyRing(KeyRepository keyRepository, Uri uri) {
mKeyRepository = keyRepository;
mUri = uri;
} }
@Override @Override
public long getMasterKeyId() throws PgpKeyNotFoundException { public long getMasterKeyId() {
try { return unifiedKeyInfo.master_key_id();
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 byte[] getFingerprint() {
* Find the master key id related to a given query. The id will either be extracted from the return unifiedKeyInfo.fingerprint();
* 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() throws PgpKeyNotFoundException { public long getCreationTime() {
try { return unifiedKeyInfo.creation();
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);
}
} }
@Override @Override
public String getPrimaryUserId() throws PgpKeyNotFoundException { public String getPrimaryUserId() {
try { return unifiedKeyInfo.user_id();
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 getPrimaryUserIdWithFallback() throws PgpKeyNotFoundException { public String getPrimaryUserIdWithFallback() {
return getPrimaryUserId(); return getPrimaryUserId();
} }
public String getName() throws PgpKeyNotFoundException { @Override
try { public boolean isRevoked() {
Object data = mKeyRepository.getGenericData(mUri, return unifiedKeyInfo.is_revoked();
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 @Override
public boolean isRevoked() throws PgpKeyNotFoundException { public boolean canCertify() {
try { return unifiedKeyInfo.can_certify();
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);
}
} }
@Override @Override
public boolean canCertify() throws PgpKeyNotFoundException { public long getEncryptId() {
try { return unifiedKeyInfo.has_encrypt_key_int();
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);
}
} }
@Override @Override
public long getEncryptId() throws PgpKeyNotFoundException { public boolean hasEncrypt() {
try { return unifiedKeyInfo.has_encrypt_key();
Object data = mKeyRepository.getGenericData(mUri,
KeyRings.HAS_ENCRYPT,
KeyRepository.FIELD_TYPE_INTEGER);
return (Long) data;
} catch(KeyWritableRepository.NotFoundException e) {
throw new PgpKeyNotFoundException(e);
} }
public long getAuthenticationId() {
return unifiedKeyInfo.has_auth_key_int();
} }
@Override @Override
public boolean hasEncrypt() throws PgpKeyNotFoundException { public VerificationStatus getVerified() {
return getEncryptId() != 0; return unifiedKeyInfo.verified();
} }
/** Returns the key id which should be used for signing. public boolean hasAnySecret() {
* return unifiedKeyInfo.has_any_secret();
* 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);
}
} }
} }

View File

@@ -21,13 +21,11 @@ package org.sufficientlysecure.keychain.provider;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri;
import com.squareup.sqldelight.SqlDelightQuery; import com.squareup.sqldelight.SqlDelightQuery;
import org.bouncycastle.bcpg.ArmoredOutputStream; 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.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; 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; import timber.log.Timber;
public class KeyRepository extends AbstractDao { 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 ContentResolver contentResolver;
final LocalPublicKeyStorage mLocalPublicKeyStorage; final LocalPublicKeyStorage mLocalPublicKeyStorage;
final LocalSecretKeyStorage localSecretKeyStorage; final LocalSecretKeyStorage localSecretKeyStorage;
@@ -115,72 +102,13 @@ public class KeyRepository extends AbstractDao {
mLog = new OperationLog(); mLog = new OperationLog();
} }
Object getGenericData(Uri uri, String column, int type) throws NotFoundException { // replace with getUnifiedKeyInfo
Object result = getGenericData(uri, new String[]{column}, new int[]{type}, null).get(column); public CachedPublicKeyRing getCachedPublicKeyRing(long masterKeyId) throws NotFoundException {
if (result == null) { UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
if (unifiedKeyInfo == null) {
throw new NotFoundException(); throw new NotFoundException();
} }
return result; return new CachedPublicKeyRing(unifiedKeyInfo);
}
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));
} }
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId) throws NotFoundException { public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId) throws NotFoundException {
@@ -211,11 +139,7 @@ public class KeyRepository extends AbstractDao {
} }
public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) { public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) {
long[] signerKeyIds = new long[signerMasterKeyIds.size()]; long[] signerKeyIds = getLongListAsArray(signerMasterKeyIds);
int i = 0;
for (Long signerKeyId : signerMasterKeyIds) {
signerKeyIds[i++] = signerKeyId;
}
SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds); SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds);
return mapAllRows(query, KeyRingPublic.FACTORY.selectAllMasterKeyIdsMapper()::map); 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) { public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%'); SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%');
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map); 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); 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); SqlDelightQuery query = SubKey.FACTORY.selectSecretKeyType(keyId);
try (Cursor cursor = getReadableDb().query(query)) { try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
return SubKey.SKT_MAPPER.map(cursor); 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(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = new ArmoredOutputStream(bos); ArmoredOutputStream aos = new ArmoredOutputStream(bos);
@@ -295,15 +224,13 @@ public class KeyRepository extends AbstractDao {
return bos.toByteArray(); return bos.toByteArray();
} }
public String getPublicKeyRingAsArmoredString(long masterKeyId) public String getPublicKeyRingAsArmoredString(long masterKeyId) throws NotFoundException, IOException {
throws NotFoundException, IOException, PgpGeneralException {
byte[] data = loadPublicKeyRingData(masterKeyId); byte[] data = loadPublicKeyRingData(masterKeyId);
byte[] armoredData = getKeyRingAsArmoredData(data); byte[] armoredData = getKeyRingAsArmoredData(data);
return new String(armoredData); return new String(armoredData);
} }
public byte[] getSecretKeyRingAsArmoredData(long masterKeyId) public byte[] getSecretKeyRingAsArmoredData(long masterKeyId) throws NotFoundException, IOException {
throws NotFoundException, IOException, PgpGeneralException {
byte[] data = loadSecretKeyRingData(masterKeyId); byte[] data = loadSecretKeyRingData(masterKeyId);
return getKeyRingAsArmoredData(data); 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 static class NotFoundException extends Exception {
public NotFoundException() { public NotFoundException() {
} }
@@ -346,4 +291,13 @@ public class KeyRepository extends AbstractDao {
super(name); 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.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.OperationApplicationException; import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.RemoteException; import android.os.RemoteException;
import android.support.annotation.NonNull; 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.KeyRingsPublicModel.DeleteByMasterKeyId;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.CustomColumnAdapters; 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.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; 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.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; 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.KeySignatures;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
@@ -99,8 +98,7 @@ public class KeyWritableRepository extends KeyRepository {
localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, autocryptPeerDao); localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, autocryptPeerDao);
} }
@VisibleForTesting private KeyWritableRepository(Context context,
KeyWritableRepository(Context context,
KeychainDatabase database, LocalPublicKeyStorage localPublicKeyStorage, KeychainDatabase database, LocalPublicKeyStorage localPublicKeyStorage,
LocalSecretKeyStorage localSecretKeyStorage, LocalSecretKeyStorage localSecretKeyStorage,
DatabaseNotifyManager databaseNotifyManager, AutocryptPeerDao autocryptPeerDao) { DatabaseNotifyManager databaseNotifyManager, AutocryptPeerDao autocryptPeerDao) {
@@ -120,27 +118,15 @@ public class KeyWritableRepository extends KeyRepository {
} }
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() { 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);
try {
LongSparseArray<CanonicalizedPublicKey> result = new LongSparseArray<>(); LongSparseArray<CanonicalizedPublicKey> result = new LongSparseArray<>();
if (cursor == null) { List<UnifiedKeyInfo> unifiedKeyInfoWithSecret = getAllUnifiedKeyInfoWithSecret();
return result; for (UnifiedKeyInfo unifiedKeyInfo : unifiedKeyInfoWithSecret) {
}
while (cursor.moveToNext()) {
try { try {
long masterKeyId = cursor.getLong(0); byte[] blob = loadPublicKeyRingData(unifiedKeyInfo.master_key_id());
long verified = cursor.getLong(2);
byte[] blob = loadPublicKeyRingData(masterKeyId);
VerificationStatus verificationStatus = CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(verified);
if (blob != null) { if (blob != null) {
result.put(masterKeyId, new CanonicalizedPublicKeyRing(blob, verificationStatus).getPublicKey()); result.put(unifiedKeyInfo.master_key_id(),
new CanonicalizedPublicKeyRing(blob, unifiedKeyInfo.verified()).getPublicKey());
} }
} catch (NotFoundException e) { } catch (NotFoundException e) {
throw new IllegalStateException("Error reading secret key data, this should not happen!", e); throw new IllegalStateException("Error reading secret key data, this should not happen!", e);
@@ -148,12 +134,6 @@ public class KeyWritableRepository extends KeyRepository {
} }
return result; return result;
} finally {
if (cursor != null) {
cursor.close();
}
}
} }
// bits, in order: CESA. make SURE these are correct, we will get bad log entries otherwise!! // 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_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_PUBLIC = "public";
public static final String PATH_USER_IDS = "user_ids"; public static final String PATH_USER_IDS = "user_ids";
public static final String PATH_KEYS = "keys"; public static final String PATH_KEYS = "keys";
@@ -132,16 +129,6 @@ public class KeychainContract {
public static Uri buildGenericKeyRingUri(long masterKeyId) { public static Uri buildGenericKeyRingUri(long masterKeyId) {
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).build(); 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 { public static class KeyRingData implements KeyRingsColumns, BaseColumns {

View File

@@ -32,7 +32,9 @@ import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.SQLException; import android.database.SQLException;
import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteException;
import android.support.annotation.VisibleForTesting;
import org.sufficientlysecure.keychain.ApiAllowedKeysModel;
import org.sufficientlysecure.keychain.ApiAppsModel; import org.sufficientlysecure.keychain.ApiAppsModel;
import org.sufficientlysecure.keychain.AutocryptPeersModel; import org.sufficientlysecure.keychain.AutocryptPeersModel;
import org.sufficientlysecure.keychain.CertsModel; import org.sufficientlysecure.keychain.CertsModel;
@@ -66,12 +68,15 @@ public class KeychainDatabase {
private static KeychainDatabase sInstance; private static KeychainDatabase sInstance;
public static KeychainDatabase getInstance(Context context) { public static KeychainDatabase getInstance(Context context) {
if (sInstance == null) {
sInstance = new KeychainDatabase(context.getApplicationContext()); sInstance = new KeychainDatabase(context.getApplicationContext());
}
return sInstance; return sInstance;
} }
@VisibleForTesting
public static void resetSingleton() {
sInstance = null;
}
public interface Tables { public interface Tables {
String KEY_RINGS_PUBLIC = "keyrings_public"; String KEY_RINGS_PUBLIC = "keyrings_public";
String KEYS = "keys"; String KEYS = "keys";
@@ -133,7 +138,7 @@ public class KeychainDatabase {
db.execSQL(ApiAppsModel.CREATE_TABLE); db.execSQL(ApiAppsModel.CREATE_TABLE);
db.execSQL(OverriddenWarningsModel.CREATE_TABLE); db.execSQL(OverriddenWarningsModel.CREATE_TABLE);
db.execSQL(AutocryptPeersModel.CREATE_TABLE); db.execSQL(AutocryptPeersModel.CREATE_TABLE);
db.execSQL(ApiAppsModel.CREATE_TABLE); db.execSQL(ApiAllowedKeysModel.CREATE_TABLE);
db.execSQL(KeysModel.UNIFIEDKEYVIEW); db.execSQL(KeysModel.UNIFIEDKEYVIEW);
db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysColumns.RANK + ", " + KeysColumns.MASTER_KEY_ID + ");"); 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! // DANGEROUS, use in test code ONLY!
public void clearDatabase() { public void clearDatabase() {
getWritableDatabase().execSQL("delete from " + Tables.KEY_RINGS_PUBLIC); getWritableDatabase().execSQL("delete from " + KeyRingsPublicModel.TABLE_NAME);
getWritableDatabase().execSQL("delete from " + Tables.API_ALLOWED_KEYS); getWritableDatabase().execSQL("delete from " + ApiAllowedKeysModel.TABLE_NAME);
getWritableDatabase().execSQL("delete from api_apps"); 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_PUBLIC = 203;
private static final int KEY_RING_CERTS = 205; 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; private static final int KEY_SIGNATURES = 700;
protected UriMatcher mUriMatcher; protected UriMatcher mUriMatcher;
@@ -88,16 +86,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
+ "/" + KeychainContract.PATH_UNIFIED, + "/" + KeychainContract.PATH_UNIFIED,
KEY_RINGS_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 * list key_ring specifics
* *
@@ -174,8 +162,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
switch (match) { switch (match) {
case KEY_RING_UNIFIED: case KEY_RING_UNIFIED:
case KEY_RINGS_UNIFIED: case KEY_RINGS_UNIFIED: {
case KEY_RINGS_FIND_BY_SUBKEY: {
HashMap<String, String> projectionMap = new HashMap<>(); HashMap<String, String> projectionMap = new HashMap<>();
projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id");
projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_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 // in case there are multiple verifying certificates
groupBy = Tables.KEYS + "." + Keys.MASTER_KEY_ID; groupBy = Tables.KEYS + "." + Keys.MASTER_KEY_ID;
switch(match) {
case KEY_RING_UNIFIED: {
qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = "); qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1)); 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;
}
}
if (TextUtils.isEmpty(sortOrder)) { if (TextUtils.isEmpty(sortOrder)) {
sortOrder = Tables.USER_PACKETS + "." + UserPackets.USER_ID + " ASC"; 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.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.SecurityProblem; import org.sufficientlysecure.keychain.pgp.SecurityProblem;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.ApiAppDao; import org.sufficientlysecure.keychain.provider.ApiAppDao;
import org.sufficientlysecure.keychain.provider.AutocryptPeerDao; import org.sufficientlysecure.keychain.provider.AutocryptPeerDao;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository; 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.KeychainExternalContract.AutocryptStatus;
import org.sufficientlysecure.keychain.provider.OverriddenWarningsRepository; import org.sufficientlysecure.keychain.provider.OverriddenWarningsRepository;
import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResult; import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResult;
@@ -139,9 +138,9 @@ public class OpenPgpService extends Service {
// get first usable subkey capable of signing // get first usable subkey capable of signing
try { try {
long signSubKeyId = mKeyRepository.getCachedPublicKeyRing(signKeyId).getSecretSignId(); long signSubKeyId = mKeyRepository.getSecretSignId(signKeyId);
pgpData.setSignatureSubKeyId(signSubKeyId); pgpData.setSignatureSubKeyId(signSubKeyId);
} catch (PgpKeyNotFoundException e) { } catch (NotFoundException e) {
throw new Exception("signing subkey not found!", e); throw new Exception("signing subkey not found!", e);
} }
} }
@@ -230,7 +229,7 @@ public class OpenPgpService extends Service {
if (signKeyId == Constants.key.none) { if (signKeyId == Constants.key.none) {
throw new Exception("No signing key given"); throw new Exception("No signing key given");
} }
long signSubKeyId = mKeyRepository.getCachedPublicKeyRing(signKeyId).getSecretSignId(); long signSubKeyId = mKeyRepository.getSecretSignId(signKeyId);
pgpData.setSignatureMasterKeyId(signKeyId) pgpData.setSignatureMasterKeyId(signKeyId)
.setSignatureSubKeyId(signSubKeyId) .setSignatureSubKeyId(signSubKeyId)
@@ -627,7 +626,8 @@ public class OpenPgpService extends Service {
} }
try { try {
CanonicalizedPublicKeyRing keyRing = mKeyRepository.getCanonicalizedPublicKeyRing(masterKeyId); CanonicalizedPublicKeyRing keyRing =
mKeyRepository.getCanonicalizedPublicKeyRing(masterKeyId);
Intent result = new Intent(); Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); 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_PRIMARY_USER_ID, userId);
result.putExtra(OpenPgpApi.RESULT_KEY_CREATION_TIME, creationTime); result.putExtra(OpenPgpApi.RESULT_KEY_CREATION_TIME, creationTime);
} catch (PgpKeyNotFoundException e) { } catch (NotFoundException e) {
Timber.e(e, "Error loading key info"); Timber.e(e, "Error loading key info");
return createErrorResultIntent(OpenPgpError.GENERIC_ERROR, e.getMessage()); 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.ApiAppDao;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository; 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.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ssh.AuthenticationData; import org.sufficientlysecure.keychain.ssh.AuthenticationData;
@@ -59,8 +60,6 @@ import timber.log.Timber;
public class SshAuthenticationService extends Service { public class SshAuthenticationService extends Service {
private static final String TAG = "SshAuthService";
private ApiPermissionHelper mApiPermissionHelper; private ApiPermissionHelper mApiPermissionHelper;
private KeyRepository mKeyRepository; private KeyRepository mKeyRepository;
private ApiAppDao mApiAppDao; private ApiAppDao mApiAppDao;
@@ -144,23 +143,18 @@ public class SshAuthenticationService extends Service {
AuthenticationData.Builder authData = AuthenticationData.builder(); AuthenticationData.Builder authData = AuthenticationData.builder();
authData.setAuthenticationMasterKeyId(masterKeyId); authData.setAuthenticationMasterKeyId(masterKeyId);
CachedPublicKeyRing cachedPublicKeyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId);
long authSubKeyId; long authSubKeyId;
int authSubKeyAlgorithm; int authSubKeyAlgorithm;
String authSubKeyCurveOid = null; String authSubKeyCurveOid = null;
try { try {
// get first usable subkey capable of authentication // get first usable subkey capable of authentication
authSubKeyId = cachedPublicKeyRing.getSecretAuthenticationId(); authSubKeyId = mKeyRepository.getSecretAuthenticationId(masterKeyId);
// needed for encoding the resulting signature // needed for encoding the resulting signature
authSubKeyAlgorithm = getPublicKey(masterKeyId).getAlgorithm(); authSubKeyAlgorithm = getPublicKey(masterKeyId).getAlgorithm();
if (authSubKeyAlgorithm == PublicKeyAlgorithmTags.ECDSA) { if (authSubKeyAlgorithm == PublicKeyAlgorithmTags.ECDSA) {
authSubKeyCurveOid = getPublicKey(masterKeyId).getCurveOid(); authSubKeyCurveOid = getPublicKey(masterKeyId).getCurveOid();
} }
} catch (PgpKeyNotFoundException e) { } catch (NotFoundException e) {
return createExceptionErrorResult(SshAuthenticationApiError.NO_AUTH_KEY,
"authentication key for master key id not found in keychain", e);
} catch (KeyRepository.NotFoundException e) {
return createExceptionErrorResult(SshAuthenticationApiError.NO_SUCH_KEY, return createExceptionErrorResult(SshAuthenticationApiError.NO_SUCH_KEY,
"Key for master key id not found", e); "Key for master key id not found", e);
} }
@@ -272,7 +266,7 @@ public class SshAuthenticationService extends Service {
try { try {
description = getDescription(masterKeyId); description = getDescription(masterKeyId);
} catch (PgpKeyNotFoundException e) { } catch (NotFoundException e) {
return createExceptionErrorResult(SshAuthenticationApiError.NO_SUCH_KEY, return createExceptionErrorResult(SshAuthenticationApiError.NO_SUCH_KEY,
"Could not create description", e); "Could not create description", e);
} }
@@ -372,8 +366,7 @@ public class SshAuthenticationService extends Service {
return new SshPublicKeyResponse(sshPublicKeyBlob).toIntent(); return new SshPublicKeyResponse(sshPublicKeyBlob).toIntent();
} }
private CanonicalizedPublicKey getPublicKey(long masterKeyId) private CanonicalizedPublicKey getPublicKey(long masterKeyId) throws NotFoundException {
throws PgpKeyNotFoundException, KeyRepository.NotFoundException {
KeyRepository keyRepository = KeyRepository.create(getApplicationContext()); KeyRepository keyRepository = KeyRepository.create(getApplicationContext());
long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId) long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId)
.getAuthenticationId(); .getAuthenticationId();
@@ -381,11 +374,11 @@ public class SshAuthenticationService extends Service {
.getPublicKey(authSubKeyId); .getPublicKey(authSubKeyId);
} }
private String getDescription(long masterKeyId) throws PgpKeyNotFoundException { private String getDescription(long masterKeyId) throws NotFoundException {
CachedPublicKeyRing cachedPublicKeyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId); CachedPublicKeyRing cachedPublicKeyRing = mKeyRepository.getCachedPublicKeyRing(masterKeyId);
String description = ""; String description = "";
long authSubKeyId = cachedPublicKeyRing.getSecretAuthenticationId(); long authSubKeyId = mKeyRepository.getSecretAuthenticationId(masterKeyId);
description += cachedPublicKeyRing.getPrimaryUserId(); description += cachedPublicKeyRing.getPrimaryUserId();
description += " (" + Long.toHexString(authSubKeyId) + ")"; description += " (" + Long.toHexString(authSubKeyId) + ")";

View File

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

View File

@@ -18,6 +18,8 @@
package org.sufficientlysecure.keychain.service; package org.sufficientlysecure.keychain.service;
import java.util.Date;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.Notification; import android.app.Notification;
import android.app.PendingIntent; import android.app.PendingIntent;
@@ -41,14 +43,11 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Constants.NotificationIds; import org.sufficientlysecure.keychain.Constants.NotificationIds;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
import timber.log.Timber; 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 * 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 * passphrase cache. Use the static methods addCachedPassphrase and getCachedPassphrase for
@@ -246,8 +245,8 @@ public class PassphraseCacheService extends Service {
+ masterKeyId + ", subKeyId " + subKeyId); + masterKeyId + ", subKeyId " + subKeyId);
// get the type of key (from the database) // get the type of key (from the database)
CachedPublicKeyRing keyRing = KeyRepository.create(this).getCachedPublicKeyRing(masterKeyId); KeyRepository keyRepository = KeyRepository.create(this);
SecretKeyType keyType = keyRing.getSecretKeyType(subKeyId); SecretKeyType keyType = keyRepository.getSecretKeyType(subKeyId);
switch (keyType) { switch (keyType) {
case PASSPHRASE_EMPTY: case PASSPHRASE_EMPTY:

View File

@@ -17,8 +17,12 @@
package org.sufficientlysecure.keychain.ssh; package org.sufficientlysecure.keychain.ssh;
import java.util.Collection;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import org.bouncycastle.openpgp.AuthenticationSignatureGenerator; import org.bouncycastle.openpgp.AuthenticationSignatureGenerator;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder; 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.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface; import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; 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;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
import timber.log.Timber; import timber.log.Timber;
import java.util.Collection;
import static java.lang.String.format; import static java.lang.String.format;
@@ -101,8 +103,8 @@ public class AuthenticationOperation extends BaseOperation<AuthenticationParcel>
Long authSubKeyId = data.getAuthenticationSubKeyId(); Long authSubKeyId = data.getAuthenticationSubKeyId();
if (authSubKeyId == null) { if (authSubKeyId == null) {
try { // Get the key id of the authentication key belonging to the master key id try { // Get the key id of the authentication key belonging to the master key id
authSubKeyId = mKeyRepository.getCachedPublicKeyRing(authMasterKeyId).getSecretAuthenticationId(); authSubKeyId = mKeyRepository.getSecretAuthenticationId(authMasterKeyId);
} catch (PgpKeyNotFoundException e) { } catch (NotFoundException e) {
log.add(LogType.MSG_AUTH_ERROR_KEY_AUTH, indent); log.add(LogType.MSG_AUTH_ERROR_KEY_AUTH, indent);
return new AuthenticationResult(AuthenticationResult.RESULT_ERROR, log); return new AuthenticationResult(AuthenticationResult.RESULT_ERROR, log);
} }
@@ -142,9 +144,7 @@ public class AuthenticationOperation extends BaseOperation<AuthenticationParcel>
CanonicalizedSecretKey.SecretKeyType secretKeyType; CanonicalizedSecretKey.SecretKeyType secretKeyType;
try { try {
secretKeyType = mKeyRepository secretKeyType = mKeyRepository.getSecretKeyType(authSubKeyId);
.getCachedPublicKeyRing(authMasterKeyId)
.getSecretKeyType(authSubKeyId);
} catch (KeyRepository.NotFoundException e) { } catch (KeyRepository.NotFoundException e) {
log.add(LogType.MSG_AUTH_ERROR_KEY_AUTH, indent); log.add(LogType.MSG_AUTH_ERROR_KEY_AUTH, indent);
return new AuthenticationResult(AuthenticationResult.RESULT_ERROR, log); 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.R;
import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; 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.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository; 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;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -75,7 +75,7 @@ public class CertifyKeyFragment
if (key.canCertify()) { if (key.canCertify()) {
mCertifyKeySpinner.setPreSelectedKeyId(certifyKeyId); mCertifyKeySpinner.setPreSelectedKeyId(certifyKeyId);
} }
} catch (PgpKeyNotFoundException e) { } catch (NotFoundException e) {
Timber.e(e, "certify certify check failed"); 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.OperationResult;
import org.sufficientlysecure.keychain.operations.results.UploadResult; import org.sufficientlysecure.keychain.operations.results.UploadResult;
import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
@@ -413,10 +413,10 @@ public class CreateKeyFinalFragment extends Fragment {
KeyRepository keyRepository = KeyRepository.create(getContext()); KeyRepository keyRepository = KeyRepository.create(getContext());
SaveKeyringParcel.Builder builder; SaveKeyringParcel.Builder builder;
CachedPublicKeyRing key = keyRepository.getCachedPublicKeyRing(saveKeyResult.mMasterKeyId);
try { try {
CachedPublicKeyRing key = keyRepository.getCachedPublicKeyRing(saveKeyResult.mMasterKeyId);
builder = SaveKeyringParcel.buildChangeKeyringParcel(saveKeyResult.mMasterKeyId, key.getFingerprint()); 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!"); Timber.e("Key that should be moved to Security Token not found in database!");
return; return;
} }

View File

@@ -38,6 +38,7 @@ import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R; 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.DeleteResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.RevokeResult; import org.sufficientlysecure.keychain.operations.results.RevokeResult;
@@ -86,36 +87,24 @@ public class DeleteKeyDialogActivity extends FragmentActivity {
if (mMasterKeyIds.length == 1 && mHasSecret) { if (mMasterKeyIds.length == 1 && mHasSecret) {
// if mMasterKeyIds.length == 0 we let the DeleteOperation respond // if mMasterKeyIds.length == 0 we let the DeleteOperation respond
try {
KeyRepository keyRepository = KeyRepository.create(this); KeyRepository keyRepository = KeyRepository.create(this);
HashMap<String, Object> data = keyRepository.getUnifiedData( UnifiedKeyInfo keyInfo = keyRepository.getUnifiedKeyInfo(mMasterKeyIds[0]);
mMasterKeyIds[0], new String[]{ if (keyInfo == null) {
KeychainContract.KeyRings.NAME, Timber.e("Secret key to delete not found at DeleteKeyDialogActivity for " + mMasterKeyIds[0]);
KeychainContract.KeyRings.IS_REVOKED finish();
}, new int[]{ return;
KeyRepository.FIELD_TYPE_STRING,
KeyRepository.FIELD_TYPE_INTEGER
} }
);
String name;
name = (String) data.get(KeychainContract.KeyRings.NAME);
String name = keyInfo.name();
if (name == null) { if (name == null) {
name = getString(R.string.user_id_no_name); name = getString(R.string.user_id_no_name);
} }
if ((long) data.get(KeychainContract.KeyRings.IS_REVOKED) > 0) { if (keyInfo.is_revoked()) {
showNormalDeleteDialog(); showNormalDeleteDialog();
} else { } else {
showRevokeDeleteDialog(name); showRevokeDeleteDialog(name);
} }
} catch (KeyRepository.NotFoundException e) {
Timber.e(e, "Secret key to delete not found at DeleteKeyDialogActivity for "
+ mMasterKeyIds[0]);
finish();
}
} else { } else {
showNormalDeleteDialog(); showNormalDeleteDialog();
} }
@@ -269,25 +258,19 @@ public class DeleteKeyDialogActivity extends FragmentActivity {
if (masterKeyIds.length == 1) { if (masterKeyIds.length == 1) {
long masterKeyId = masterKeyIds[0]; long masterKeyId = masterKeyIds[0];
try { KeyRepository keyRepository = KeyRepository.create(getContext());
HashMap<String, Object> data = KeyRepository.create(getContext()) UnifiedKeyInfo keyInfo = keyRepository.getUnifiedKeyInfo(masterKeyId);
.getUnifiedData( if (keyInfo == null) {
masterKeyId, new String[]{ dismiss();
KeychainContract.KeyRings.NAME, return null;
KeychainContract.KeyRings.HAS_ANY_SECRET
}, new int[]{
KeyRepository.FIELD_TYPE_STRING,
KeyRepository.FIELD_TYPE_INTEGER
} }
); String name = keyInfo.name();
String name;
name = (String) data.get(KeychainContract.KeyRings.NAME);
if (name == null) { if (name == null) {
name = getString(R.string.user_id_no_name); name = getString(R.string.user_id_no_name);
} }
if (hasSecret) { if (keyInfo.has_any_secret()) {
// show title only for secret key deletions, // show title only for secret key deletions,
// see http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior // see http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior
builder.setTitle(getString(R.string.title_delete_secret_key, name)); builder.setTitle(getString(R.string.title_delete_secret_key, name));
@@ -295,10 +278,6 @@ public class DeleteKeyDialogActivity extends FragmentActivity {
} else { } else {
mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name)); mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name));
} }
} catch (KeyRepository.NotFoundException e) {
dismiss();
return null;
}
} else { } else {
mMainMessage.setText(R.string.key_deletion_confirmation_multi); 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.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
@@ -142,7 +141,7 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
if (keyring.hasAnySecret()) { if (keyring.hasAnySecret()) {
mSignKeySpinner.setPreSelectedKeyId(signatureKeyId); mSignKeySpinner.setPreSelectedKeyId(signatureKeyId);
} }
} catch (PgpKeyNotFoundException e) { } catch (NotFoundException e) {
Timber.e(e, "key not found for signing!"); Timber.e(e, "key not found for signing!");
Notify.create(getActivity(), getString(R.string.error_preselect_sign_key, Notify.create(getActivity(), getString(R.string.error_preselect_sign_key,
KeyFormattingUtils.beautifyKeyId(signatureKeyId)), 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.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; 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 // handle empty passphrases by directly returning an empty crypto input parcel
try { try {
CachedPublicKeyRing pubRing = KeyRepository keyRepository = KeyRepository.create(this);
KeyRepository.create(this).getCachedPublicKeyRing(requiredInput.getMasterKeyId());
// use empty passphrase for empty passphrase // 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 // also return passphrase back to activity
Intent returnIntent = new Intent(); Intent returnIntent = new Intent();
cryptoInputParcel = cryptoInputParcel.withPassphrase(new Passphrase(""), requiredInput.getSubKeyId()); cryptoInputParcel = cryptoInputParcel.withPassphrase(new Passphrase(""), requiredInput.getSubKeyId());
@@ -299,7 +297,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
userId = getString(R.string.user_id_no_name); userId = getString(R.string.user_id_no_name);
} }
keyType = cachedPublicKeyRing.getSecretKeyType(subKeyId); keyType = keyRepository.getSecretKeyType(subKeyId);
switch (keyType) { switch (keyType) {
case PASSPHRASE: case PASSPHRASE:
message = getString(R.string.passphrase_for, userId); message = getString(R.string.passphrase_for, userId);
@@ -316,7 +314,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
throw new AssertionError("Unhandled SecretKeyType (should not happen)"); 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.setTitle(R.string.title_key_not_found);
alert.setMessage(getString(R.string.key_not_found, mRequiredInput.getSubKeyId())); alert.setMessage(getString(R.string.key_not_found, mRequiredInput.getSubKeyId()));
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 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.model.Certification.CertDetails;
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; 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;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter; import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
@@ -382,9 +382,8 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements OnB
byte[] fingerprint; byte[] fingerprint;
try { try {
fingerprint = KeyRepository.create(activity).getCachedPublicKeyRing( fingerprint = KeyRepository.create(activity).getCachedPublicKeyRing(masterKeyId).getFingerprint();
masterKeyId).getFingerprint(); } catch (NotFoundException e) {
} catch (PgpKeyNotFoundException e) {
throw new IllegalStateException("Key to verify linked id for must exist in db!"); 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() { private boolean keyHasPassphrase() {
try { try {
long masterKeyId = unifiedKeyInfo.master_key_id(); long masterKeyId = unifiedKeyInfo.master_key_id();
SecretKeyType secretKeyType = SecretKeyType secretKeyType = keyRepository.getSecretKeyType(masterKeyId);
keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretKeyType(masterKeyId);
switch (secretKeyType) { switch (secretKeyType) {
// all of these make no sense to ask // all of these make no sense to ask
case PASSPHRASE_EMPTY: case PASSPHRASE_EMPTY:

View File

@@ -29,14 +29,12 @@ import android.os.SystemClock;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.AsyncTaskLoader;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import okhttp3.Call; import okhttp3.Call;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.Request.Builder; import okhttp3.Request.Builder;
import okhttp3.Response; import okhttp3.Response;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient;
import org.sufficientlysecure.keychain.keyimport.KeyserverClient.QueryFailedException; 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;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; 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;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; 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.token.PublicKeyRetrievalLoader.KeyRetrievalResult;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ParcelableProxy; 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); log.add(LogType.MSG_RET_LOCAL_NOT_FOUND, 2);
continue; continue;
} }
CachedPublicKeyRing cachedPublicKeyRing = keyRepository.getCachedPublicKeyRing(masterKeyId);
// TODO check fingerprint // TODO check fingerprint
// if (!Arrays.equals(fingerprints, cachedPublicKeyRing.getFingerprint())) { // 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); // log.add(LogType.MSG_RET_LOCAL_FP_MATCH, 1);
// } // }
switch (cachedPublicKeyRing.getSecretKeyType(keyId)) { switch (keyRepository.getSecretKeyType(keyId)) {
case PASSPHRASE: case PASSPHRASE:
case PASSPHRASE_EMPTY: { case PASSPHRASE_EMPTY: {
log.add(LogType.MSG_RET_LOCAL_SECRET, 1); 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); byte[] armoredSecretKey = databaseInteractor.getSecretKeyRingAsArmoredData(masterKeyId);
secretKeyAdapter.focusItem(masterKeyId); secretKeyAdapter.focusItem(masterKeyId);
connectionSend(armoredSecretKey, Long.toString(masterKeyId)); connectionSend(armoredSecretKey, Long.toString(masterKeyId));
} catch (IOException | NotFoundException | PgpGeneralException e) { } catch (IOException | NotFoundException e) {
// TODO // TODO
e.printStackTrace(); e.printStackTrace();
} }

View File

@@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS certs(
rank INTEGER NOT NULL, rank INTEGER NOT NULL,
key_id_certifier INTEGER NOT NULL, key_id_certifier INTEGER NOT NULL,
type INTEGER NOT NULL, type INTEGER NOT NULL,
verified INTEGER AS VerificationStatus NOT NULL, verified INTEGER AS VerificationStatus NOT NULL DEFAULT 0,
creation INTEGER NOT NULL, creation INTEGER NOT NULL,
data BLOB NOT NULL, data BLOB NOT NULL,
PRIMARY KEY(master_key_id, rank, key_id_certifier), PRIMARY KEY(master_key_id, rank, key_id_certifier),

View File

@@ -14,7 +14,7 @@ CREATE TABLE IF NOT EXISTS keys (
can_encrypt INTEGER AS Boolean NOT NULL, can_encrypt INTEGER AS Boolean NOT NULL,
can_authenticate INTEGER AS Boolean NOT NULL, can_authenticate INTEGER AS Boolean NOT NULL,
is_revoked INTEGER AS Boolean NOT NULL, is_revoked INTEGER AS Boolean NOT NULL,
has_secret INTEGER AS SecretKeyType NOT NULL, has_secret INTEGER AS SecretKeyType NOT NULL DEFAULT 0,
is_secure INTEGER AS Boolean NOT NULL, is_secure INTEGER AS Boolean NOT NULL,
creation INTEGER NOT NULL, creation INTEGER NOT NULL,
expiry INTEGER, expiry INTEGER,
@@ -25,11 +25,12 @@ CREATE TABLE IF NOT EXISTS keys (
unifiedKeyView: unifiedKeyView:
CREATE VIEW unifiedKeyView AS CREATE VIEW unifiedKeyView AS
SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, certs.verified, SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
(EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate_int, (EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate_int,
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0 )) AS has_any_secret_int, (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0 )) AS has_any_secret_int,
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0 )) AS has_auth_key_int, (SELECT key_id FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_encrypt != 0 LIMIT 1) AS has_encrypt_key_int,
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_encrypt != 0 )) AS has_encrypt_key_int, (SELECT key_id FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_sign != 0 LIMIT 1) AS has_sign_key_int,
(SELECT key_id FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0 LIMIT 1) AS has_auth_key_int,
GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv, GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv,
GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list
FROM keys FROM keys
@@ -47,6 +48,10 @@ selectUnifiedKeyInfoByMasterKeyId:
SELECT * FROM unifiedKeyView SELECT * FROM unifiedKeyView
WHERE is_revoked = 0 AND master_key_id = ?; WHERE is_revoked = 0 AND master_key_id = ?;
selectUnifiedKeyInfoByMasterKeyIds:
SELECT * FROM unifiedKeyView
WHERE is_revoked = 0 AND master_key_id IN ?;
selectUnifiedKeyInfoSearchMailAddress: selectUnifiedKeyInfoSearchMailAddress:
SELECT * FROM unifiedKeyView SELECT * FROM unifiedKeyView
WHERE email LIKE ? WHERE email LIKE ?
@@ -73,6 +78,18 @@ SELECT has_secret
FROM keys FROM keys
WHERE key_id = ?; WHERE key_id = ?;
selectEffectiveSignKeyIdByMasterKeyId:
SELECT key_id
FROM keys
WHERE is_revoked = 0 AND is_secure = 1 AND has_secret > 1 AND ( expiry IS NULL OR expiry >= date('now') )
AND can_sign = 1 AND master_key_id = ?;
selectEffectiveAuthKeyIdByMasterKeyId:
SELECT key_id
FROM keys
WHERE is_revoked = 0 AND is_secure = 1 AND has_secret > 1 AND ( expiry IS NULL OR expiry >= date('now') )
AND can_authenticate = 1 AND master_key_id = ?;
-- TODO move to KeySignatures.sq -- TODO move to KeySignatures.sq
selectMasterKeyIdsBySigner: selectMasterKeyIdsBySigner:
SELECT master_key_id SELECT master_key_id

View File

@@ -1,5 +1,6 @@
package org.sufficientlysecure.keychain; package org.sufficientlysecure.keychain;
import org.junit.runners.model.InitializationError; import org.junit.runners.model.InitializationError;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;

View File

@@ -19,6 +19,13 @@
package org.sufficientlysecure.keychain.operations; package org.sufficientlysecure.keychain.operations;
import java.io.PrintStream;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.util.ArrayList;
import org.bouncycastle.bcpg.HashAlgorithmTags; import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.jcajce.provider.asymmetric.eddsa.EdDSAEngine; import org.bouncycastle.jcajce.provider.asymmetric.eddsa.EdDSAEngine;
import org.bouncycastle.jcajce.provider.asymmetric.eddsa.spec.EdDSANamedCurveTable; import org.bouncycastle.jcajce.provider.asymmetric.eddsa.spec.EdDSANamedCurveTable;
@@ -44,13 +51,6 @@ import org.sufficientlysecure.keychain.ssh.AuthenticationResult;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper; import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
import java.io.PrintStream;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.util.ArrayList;
@RunWith(KeychainTestRunner.class) @RunWith(KeychainTestRunner.class)
public class AuthenticationOperationTest { public class AuthenticationOperationTest {
@@ -160,7 +160,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application); KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingRsa.getMasterKeyId(); long masterKeyId = mStaticRingRsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId(); Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge { // sign challenge
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application, AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,
@@ -206,7 +206,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application); KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingEcDsa.getMasterKeyId(); long masterKeyId = mStaticRingEcDsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId(); Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge { // sign challenge
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application, AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,
@@ -252,7 +252,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application); KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingEdDsa.getMasterKeyId(); long masterKeyId = mStaticRingEdDsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId(); Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge { // sign challenge
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application, AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,
@@ -300,7 +300,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application); KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingDsa.getMasterKeyId(); long masterKeyId = mStaticRingDsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId(); Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge { // sign challenge
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application, AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,
@@ -345,7 +345,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application); KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingEcDsa.getMasterKeyId(); long masterKeyId = mStaticRingEcDsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId(); Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge - should succeed with selected key allowed { // sign challenge - should succeed with selected key allowed
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application, AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,

View File

@@ -162,15 +162,6 @@ public class BackupOperationTest {
assertTrue("export must be a success", result); assertTrue("export must be a success", result);
long masterKeyId1, masterKeyId2;
if (mStaticRing1.getMasterKeyId() < mStaticRing2.getMasterKeyId()) {
masterKeyId1 = mStaticRing1.getMasterKeyId();
masterKeyId2 = mStaticRing2.getMasterKeyId();
} else {
masterKeyId2 = mStaticRing1.getMasterKeyId();
masterKeyId1 = mStaticRing2.getMasterKeyId();
}
IteratorWithIOThrow<UncachedKeyRing> unc = IteratorWithIOThrow<UncachedKeyRing> unc =
UncachedKeyRing.fromStream(new ByteArrayInputStream(out.toByteArray())); UncachedKeyRing.fromStream(new ByteArrayInputStream(out.toByteArray()));
@@ -178,7 +169,7 @@ public class BackupOperationTest {
assertTrue("export must have two keys (1/2)", unc.hasNext()); assertTrue("export must have two keys (1/2)", unc.hasNext());
UncachedKeyRing ring = unc.next(); UncachedKeyRing ring = unc.next();
Assert.assertEquals("first exported key has correct masterkeyid", Assert.assertEquals("first exported key has correct masterkeyid",
masterKeyId1, ring.getMasterKeyId()); mStaticRing2.getMasterKeyId(), ring.getMasterKeyId());
assertFalse("first exported key must not be secret", ring.isSecret()); assertFalse("first exported key must not be secret", ring.isSecret());
assertFalse("there must be no local signatures in an exported keyring", assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring)); checkForLocal(ring));
@@ -188,7 +179,7 @@ public class BackupOperationTest {
assertTrue("export must have two keys (2/2)", unc.hasNext()); assertTrue("export must have two keys (2/2)", unc.hasNext());
UncachedKeyRing ring = unc.next(); UncachedKeyRing ring = unc.next();
Assert.assertEquals("second exported key has correct masterkeyid", Assert.assertEquals("second exported key has correct masterkeyid",
masterKeyId2, ring.getMasterKeyId()); mStaticRing1.getMasterKeyId(), ring.getMasterKeyId());
assertFalse("second exported key must not be secret", ring.isSecret()); assertFalse("second exported key must not be secret", ring.isSecret());
assertFalse("there must be no local signatures in an exported keyring", assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring)); checkForLocal(ring));
@@ -205,7 +196,7 @@ public class BackupOperationTest {
assertTrue("export must have four keys (1/4)", unc.hasNext()); assertTrue("export must have four keys (1/4)", unc.hasNext());
UncachedKeyRing ring = unc.next(); UncachedKeyRing ring = unc.next();
Assert.assertEquals("1/4 exported key has correct masterkeyid", Assert.assertEquals("1/4 exported key has correct masterkeyid",
masterKeyId1, ring.getMasterKeyId()); mStaticRing2.getMasterKeyId(), ring.getMasterKeyId());
assertFalse("1/4 exported key must not be public", ring.isSecret()); assertFalse("1/4 exported key must not be public", ring.isSecret());
assertFalse("there must be no local signatures in an exported keyring", assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring)); checkForLocal(ring));
@@ -213,7 +204,7 @@ public class BackupOperationTest {
assertTrue("export must have four keys (2/4)", unc.hasNext()); assertTrue("export must have four keys (2/4)", unc.hasNext());
ring = unc.next(); ring = unc.next();
Assert.assertEquals("2/4 exported key has correct masterkeyid", Assert.assertEquals("2/4 exported key has correct masterkeyid",
masterKeyId1, ring.getMasterKeyId()); mStaticRing2.getMasterKeyId(), ring.getMasterKeyId());
assertTrue("2/4 exported key must be public", ring.isSecret()); assertTrue("2/4 exported key must be public", ring.isSecret());
assertFalse("there must be no local signatures in an exported keyring", assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring)); checkForLocal(ring));
@@ -223,7 +214,7 @@ public class BackupOperationTest {
assertTrue("export must have four keys (3/4)", unc.hasNext()); assertTrue("export must have four keys (3/4)", unc.hasNext());
UncachedKeyRing ring = unc.next(); UncachedKeyRing ring = unc.next();
Assert.assertEquals("3/4 exported key has correct masterkeyid", Assert.assertEquals("3/4 exported key has correct masterkeyid",
masterKeyId2, ring.getMasterKeyId()); mStaticRing1.getMasterKeyId(), ring.getMasterKeyId());
assertFalse("3/4 exported key must not be public", ring.isSecret()); assertFalse("3/4 exported key must not be public", ring.isSecret());
assertFalse("there must be no local signatures in an exported keyring", assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring)); checkForLocal(ring));
@@ -231,7 +222,7 @@ public class BackupOperationTest {
assertTrue("export must have four keys (4/4)", unc.hasNext()); assertTrue("export must have four keys (4/4)", unc.hasNext());
ring = unc.next(); ring = unc.next();
Assert.assertEquals("4/4 exported key has correct masterkeyid", Assert.assertEquals("4/4 exported key has correct masterkeyid",
masterKeyId2, ring.getMasterKeyId()); mStaticRing1.getMasterKeyId(), ring.getMasterKeyId());
assertTrue("4/4 exported key must be public", ring.isSecret()); assertTrue("4/4 exported key must be public", ring.isSecret());
assertFalse("there must be no local signatures in an exported keyring", assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring)); checkForLocal(ring));

View File

@@ -149,8 +149,8 @@ public class CertifyOperationTest {
{ {
CanonicalizedPublicKeyRing ring = KeyWritableRepository.create(RuntimeEnvironment.application) CanonicalizedPublicKeyRing ring = KeyWritableRepository.create(RuntimeEnvironment.application)
.getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId()); .getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId());
Assert.assertEquals("public key must not be marked verified prior to certification", Assert.assertNull("public key must not be marked verified prior to certification",
VerificationStatus.UNVERIFIED, ring.getVerified()); ring.getVerified());
} }
CertifyActionsParcel.Builder actions = CertifyActionsParcel.builder(mStaticRing1.getMasterKeyId()); CertifyActionsParcel.Builder actions = CertifyActionsParcel.builder(mStaticRing1.getMasterKeyId());
@@ -164,21 +164,20 @@ public class CertifyOperationTest {
CanonicalizedPublicKeyRing ring = KeyWritableRepository.create(RuntimeEnvironment.application) CanonicalizedPublicKeyRing ring = KeyWritableRepository.create(RuntimeEnvironment.application)
.getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId()); .getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId());
Assert.assertEquals("new key must be verified now", Assert.assertEquals("new key must be verified now",
VerificationStatus.UNVERIFIED, ring.getVerified()); VerificationStatus.VERIFIED_SECRET, ring.getVerified());
} }
} }
@Test @Test
public void testCertifyAttribute() throws Exception { public void testCertifyAttribute() throws Exception {
CertifyOperation op = new CertifyOperation(RuntimeEnvironment.application, KeyWritableRepository keyWritableRepository = KeyWritableRepository.create(RuntimeEnvironment.application);
KeyWritableRepository.create(RuntimeEnvironment.application), null, null); CertifyOperation op = new CertifyOperation(RuntimeEnvironment.application, keyWritableRepository, null, null);
{ {
CanonicalizedPublicKeyRing ring = KeyWritableRepository.create(RuntimeEnvironment.application) CanonicalizedPublicKeyRing ring = keyWritableRepository.getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId());
.getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId()); Assert.assertNull("public key must not be marked verified prior to certification",
Assert.assertEquals("public key must not be marked verified prior to certification", ring.getVerified());
VerificationStatus.UNVERIFIED, ring.getVerified());
} }
CertifyActionsParcel.Builder actions = CertifyActionsParcel.builder(mStaticRing1.getMasterKeyId()); CertifyActionsParcel.Builder actions = CertifyActionsParcel.builder(mStaticRing1.getMasterKeyId());
@@ -189,8 +188,7 @@ public class CertifyOperationTest {
Assert.assertTrue("certification must succeed", result.success()); Assert.assertTrue("certification must succeed", result.success());
{ {
CanonicalizedPublicKeyRing ring = KeyWritableRepository.create(RuntimeEnvironment.application) CanonicalizedPublicKeyRing ring = keyWritableRepository.getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId());
.getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId());
Assert.assertEquals("new key must be verified now", Assert.assertEquals("new key must be verified now",
VerificationStatus.VERIFIED_SECRET, ring.getVerified()); VerificationStatus.VERIFIED_SECRET, ring.getVerified());
} }

View File

@@ -105,8 +105,9 @@ public class PromoteKeyOperationTest {
@Test @Test
public void testPromote() throws Exception { public void testPromote() throws Exception {
KeyWritableRepository keyRepository = KeyWritableRepository.create(RuntimeEnvironment.application);
PromoteKeyOperation op = new PromoteKeyOperation(RuntimeEnvironment.application, PromoteKeyOperation op = new PromoteKeyOperation(RuntimeEnvironment.application,
KeyWritableRepository.create(RuntimeEnvironment.application), null, null); keyRepository, null, null);
PromoteKeyResult result = op.execute( PromoteKeyResult result = op.execute(
PromoteKeyringParcel.createPromoteKeyringParcel(mStaticRing.getMasterKeyId(), null, null), null); PromoteKeyringParcel.createPromoteKeyringParcel(mStaticRing.getMasterKeyId(), null, null), null);
@@ -114,15 +115,14 @@ public class PromoteKeyOperationTest {
Assert.assertTrue("promotion must succeed", result.success()); Assert.assertTrue("promotion must succeed", result.success());
{ {
CachedPublicKeyRing ring = KeyWritableRepository.create(RuntimeEnvironment.application) CachedPublicKeyRing ring = keyRepository.getCachedPublicKeyRing(mStaticRing.getMasterKeyId());
.getCachedPublicKeyRing(mStaticRing.getMasterKeyId());
Assert.assertTrue("key must have a secret now", ring.hasAnySecret()); Assert.assertTrue("key must have a secret now", ring.hasAnySecret());
Iterator<UncachedPublicKey> it = mStaticRing.getPublicKeys(); Iterator<UncachedPublicKey> it = mStaticRing.getPublicKeys();
while (it.hasNext()) { while (it.hasNext()) {
long keyId = it.next().getKeyId(); long keyId = it.next().getKeyId();
Assert.assertEquals("all subkeys must be gnu dummy", Assert.assertEquals("all subkeys must be gnu dummy",
SecretKeyType.GNU_DUMMY, ring.getSecretKeyType(keyId)); SecretKeyType.GNU_DUMMY, keyRepository.getSecretKeyType(keyId));
} }
} }

View File

@@ -36,6 +36,7 @@ import org.bouncycastle.bcpg.PublicKeyEncSessionPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.sig.KeyFlags; import org.bouncycastle.bcpg.sig.KeyFlags;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@@ -54,7 +55,7 @@ import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureBitStrength;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureEncryptionAlgorithm; import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureEncryptionAlgorithm;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.MissingMdc; import org.sufficientlysecure.keychain.pgp.SecurityProblem.MissingMdc;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository; import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;

View File

@@ -55,6 +55,7 @@ import org.sufficientlysecure.keychain.KeychainTestRunner;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
@@ -672,7 +673,7 @@ public class PgpKeyOperationTest {
resetBuilder(); resetBuilder();
builder.addRevokeSubkey(123L); builder.addRevokeSubkey(123L);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), 0); CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), VerificationStatus.UNVERIFIED);
UncachedKeyRing otherModified = op.modifySecretKeyRing(secretRing, cryptoInput, builder.build()).getRing(); UncachedKeyRing otherModified = op.modifySecretKeyRing(secretRing, cryptoInput, builder.build()).getRing();
Assert.assertNull("revoking a nonexistent subkey should fail", otherModified); Assert.assertNull("revoking a nonexistent subkey should fail", otherModified);
@@ -869,7 +870,7 @@ public class PgpKeyOperationTest {
securityTokenBuilder.addOrReplaceSubkeyChange(SubkeyChange.createMoveToSecurityTokenChange(keyId)); securityTokenBuilder.addOrReplaceSubkeyChange(SubkeyChange.createMoveToSecurityTokenChange(keyId));
CanonicalizedSecretKeyRing secretRing = CanonicalizedSecretKeyRing secretRing =
new CanonicalizedSecretKeyRing(ringSecurityToken.getEncoded(), 0); new CanonicalizedSecretKeyRing(ringSecurityToken.getEncoded(), VerificationStatus.UNVERIFIED);
PgpKeyOperation op = new PgpKeyOperation(null); PgpKeyOperation op = new PgpKeyOperation(null);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, securityTokenBuilder.build()); PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, securityTokenBuilder.build());
Assert.assertTrue("moveKeyToSecurityToken operation should be pending", result.isPending()); Assert.assertTrue("moveKeyToSecurityToken operation should be pending", result.isPending());
@@ -904,7 +905,7 @@ public class PgpKeyOperationTest {
securityTokenBuilder.addOrReplaceSubkeyChange(SubkeyChange.createRecertifyChange(keyId, true)); securityTokenBuilder.addOrReplaceSubkeyChange(SubkeyChange.createRecertifyChange(keyId, true));
CanonicalizedSecretKeyRing secretRing = CanonicalizedSecretKeyRing secretRing =
new CanonicalizedSecretKeyRing(modified.getEncoded(), 0); new CanonicalizedSecretKeyRing(modified.getEncoded(), VerificationStatus.UNVERIFIED);
PgpKeyOperation op = new PgpKeyOperation(null); PgpKeyOperation op = new PgpKeyOperation(null);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, securityTokenBuilder.build()); PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, securityTokenBuilder.build());
Assert.assertTrue("moveKeyToSecurityToken operation should be pending", result.isPending()); Assert.assertTrue("moveKeyToSecurityToken operation should be pending", result.isPending());
@@ -1187,7 +1188,7 @@ public class PgpKeyOperationTest {
// we should still be able to modify it (and change its passphrase) without errors // we should still be able to modify it (and change its passphrase) without errors
PgpKeyOperation op = new PgpKeyOperation(null); PgpKeyOperation op = new PgpKeyOperation(null);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), 0); CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), VerificationStatus.UNVERIFIED);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, otherCryptoInput, builder.build()); PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, otherCryptoInput, builder.build());
Assert.assertTrue("key modification must succeed", result.success()); Assert.assertTrue("key modification must succeed", result.success());
Assert.assertFalse("log must not contain a warning", Assert.assertFalse("log must not contain a warning",
@@ -1201,7 +1202,7 @@ public class PgpKeyOperationTest {
modified = KeyringTestingHelper.injectPacket(modified, sKeyWithPassphrase.buf, sKeyWithPassphrase.position); modified = KeyringTestingHelper.injectPacket(modified, sKeyWithPassphrase.buf, sKeyWithPassphrase.position);
PgpKeyOperation op = new PgpKeyOperation(null); PgpKeyOperation op = new PgpKeyOperation(null);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), 0); CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), VerificationStatus.UNVERIFIED);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, PgpEditKeyResult result = op.modifySecretKeyRing(secretRing,
CryptoInputParcel.createCryptoInputParcel(otherPassphrase2), builder.build()); CryptoInputParcel.createCryptoInputParcel(otherPassphrase2), builder.build());
Assert.assertTrue("key modification must succeed", result.success()); Assert.assertTrue("key modification must succeed", result.success());
@@ -1214,7 +1215,7 @@ public class PgpKeyOperationTest {
@Test @Test
public void testRestricted() throws Exception { public void testRestricted() throws Exception {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), 0); CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), VerificationStatus.UNVERIFIED);
builder.addUserId("discord"); builder.addUserId("discord");
PgpKeyOperation op = new PgpKeyOperation(null); PgpKeyOperation op = new PgpKeyOperation(null);
@@ -1250,7 +1251,7 @@ public class PgpKeyOperationTest {
try { try {
Assert.assertTrue("modified keyring must be secret", ring.isSecret()); Assert.assertTrue("modified keyring must be secret", ring.isSecret());
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), 0); CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), VerificationStatus.UNVERIFIED);
PgpKeyOperation op = new PgpKeyOperation(null); PgpKeyOperation op = new PgpKeyOperation(null);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel); PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
@@ -1323,7 +1324,7 @@ public class PgpKeyOperationTest {
SaveKeyringParcel parcel, CryptoInputParcel cryptoInput, LogType expected) SaveKeyringParcel parcel, CryptoInputParcel cryptoInput, LogType expected)
throws Exception { throws Exception {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), 0); CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), VerificationStatus.UNVERIFIED);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel); PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
Assert.assertFalse(reason, result.success()); Assert.assertFalse(reason, result.success());
@@ -1337,7 +1338,7 @@ public class PgpKeyOperationTest {
LogType expected) LogType expected)
throws Exception { throws Exception {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), 0); CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), VerificationStatus.UNVERIFIED);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel); PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
Assert.assertFalse(reason, result.success()); Assert.assertFalse(reason, result.success());

View File

@@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.KeychainTestRunner;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation.PgpCertifyResult; import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation.PgpCertifyResult;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
@@ -188,7 +189,7 @@ public class UncachedKeyringMergeTest {
UncachedKeyRing modifiedA, modifiedB; { UncachedKeyRing modifiedA, modifiedB; {
CanonicalizedSecretKeyRing secretRing = CanonicalizedSecretKeyRing secretRing =
new CanonicalizedSecretKeyRing(ringA.getEncoded(), 0); new CanonicalizedSecretKeyRing(ringA.getEncoded(), VerificationStatus.UNVERIFIED);
resetBuilder(); resetBuilder();
builder.addUserId("flim"); builder.addUserId("flim");
@@ -230,7 +231,7 @@ public class UncachedKeyringMergeTest {
UncachedKeyRing modifiedA, modifiedB; UncachedKeyRing modifiedA, modifiedB;
long subKeyIdA, subKeyIdB; long subKeyIdA, subKeyIdB;
{ {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ringA.getEncoded(), 0); CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ringA.getEncoded(), VerificationStatus.UNVERIFIED);
resetBuilder(); resetBuilder();
builder.addSubkeyAdd(SubkeyAdd.createSubkeyAdd( builder.addSubkeyAdd(SubkeyAdd.createSubkeyAdd(
@@ -278,7 +279,7 @@ public class UncachedKeyringMergeTest {
resetBuilder(); resetBuilder();
builder.addRevokeSubkey(KeyringTestingHelper.getSubkeyId(ringA, 1)); builder.addRevokeSubkey(KeyringTestingHelper.getSubkeyId(ringA, 1));
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing( CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
ringA.getEncoded(), 0); ringA.getEncoded(), VerificationStatus.UNVERIFIED);
modified = op.modifySecretKeyRing(secretRing, modified = op.modifySecretKeyRing(secretRing,
CryptoInputParcel.createCryptoInputParcel(new Date(), new Passphrase()), builder.build()).getRing(); CryptoInputParcel.createCryptoInputParcel(new Date(), new Passphrase()), builder.build()).getRing();
} }
@@ -301,10 +302,10 @@ public class UncachedKeyringMergeTest {
final UncachedKeyRing modified; { final UncachedKeyRing modified; {
CanonicalizedPublicKeyRing publicRing = new CanonicalizedPublicKeyRing( CanonicalizedPublicKeyRing publicRing = new CanonicalizedPublicKeyRing(
pubRing.getEncoded(), 0); pubRing.getEncoded(), VerificationStatus.UNVERIFIED);
CanonicalizedSecretKey secretKey = new CanonicalizedSecretKeyRing( CanonicalizedSecretKey secretKey = new CanonicalizedSecretKeyRing(
ringB.getEncoded(), 0).getSecretKey(); ringB.getEncoded(), VerificationStatus.UNVERIFIED).getSecretKey();
secretKey.unlock(new Passphrase()); secretKey.unlock(new Passphrase());
PgpCertifyOperation op = new PgpCertifyOperation(); PgpCertifyOperation op = new PgpCertifyOperation();
CertifyAction action = CertifyAction.createForUserIds( CertifyAction action = CertifyAction.createForUserIds(
@@ -379,7 +380,7 @@ public class UncachedKeyringMergeTest {
builder.addUserAttribute(uat); builder.addUserAttribute(uat);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing( CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
ringA.getEncoded(), 0); ringA.getEncoded(), VerificationStatus.UNVERIFIED);
modified = op.modifySecretKeyRing(secretRing, modified = op.modifySecretKeyRing(secretRing,
CryptoInputParcel.createCryptoInputParcel(new Date(), new Passphrase()), builder.build()).getRing(); CryptoInputParcel.createCryptoInputParcel(new Date(), new Passphrase()), builder.build()).getRing();
} }

View File

@@ -27,8 +27,6 @@ import java.net.URL;
import java.security.Security; import java.security.Security;
import java.util.ArrayList; import java.util.ArrayList;
import android.net.Uri;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
@@ -45,14 +43,9 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
@@ -62,7 +55,7 @@ import org.sufficientlysecure.keychain.util.Passphrase;
public class InteropTest { public class InteropTest {
@BeforeClass @BeforeClass
public static void setUpOnce() throws Exception { public static void setUpOnce() {
Security.insertProviderAt(new BouncyCastleProvider(), 1); Security.insertProviderAt(new BouncyCastleProvider(), 1);
ShadowLog.stream = System.out; ShadowLog.stream = System.out;
} }
@@ -104,11 +97,11 @@ public class InteropTest {
} }
} }
private static final String asString(File json) throws Exception { private static String asString(File json) throws Exception {
return new String(asBytes(json), "utf-8"); return new String(asBytes(json), "utf-8");
} }
private static final byte[] asBytes(File f) throws Exception { private static byte[] asBytes(File f) throws Exception {
FileInputStream fin = null; FileInputStream fin = null;
try { try {
fin = new FileInputStream(f); fin = new FileInputStream(f);
@@ -123,16 +116,14 @@ public class InteropTest {
private void runDecryptTest(JSONObject config, File base) throws Exception { private void runDecryptTest(JSONObject config, File base) throws Exception {
File root = base.getParentFile(); File root = base.getParentFile();
String baseName = getBaseName(base); String baseName = getBaseName(base);
CanonicalizedPublicKeyRing verify; UncachedKeyRing verify;
if (config.has("verifyKey")) { if (config.has("verifyKey")) {
verify = (CanonicalizedPublicKeyRing) verify = readUncachedRingFromFile(new File(root, config.getString("verifyKey")));
readRingFromFile(new File(root, config.getString("verifyKey")));
} else { } else {
verify = null; verify = null;
} }
CanonicalizedSecretKeyRing decrypt = (CanonicalizedSecretKeyRing) UncachedKeyRing decrypt = readUncachedRingFromFile(new File(root, config.getString("decryptKey")));
readRingFromFile(new File(root, config.getString("decryptKey")));
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = ByteArrayInputStream in =
@@ -154,9 +145,10 @@ public class InteropTest {
if (verify != null) { if (verify != null) {
// Certain keys are too short, so we check appropriately. // Certain keys are too short, so we check appropriately.
int code = result.getSignatureResult().getResult(); int code = result.getSignatureResult().getResult();
Assert.assertTrue(base + ": should have a signature", Assert.assertTrue(base + ": should have a signature (code: " + code + ")",
(code == OpenPgpSignatureResult.RESULT_INVALID_KEY_INSECURE) || code == OpenPgpSignatureResult.RESULT_INVALID_KEY_INSECURE ||
(code == OpenPgpSignatureResult.RESULT_VALID_KEY_UNCONFIRMED)); code == OpenPgpSignatureResult.RESULT_VALID_KEY_UNCONFIRMED
|| code == OpenPgpSignatureResult.RESULT_VALID_KEY_CONFIRMED);
} }
OpenPgpMetadata metadata = result.getDecryptionMetadata(); OpenPgpMetadata metadata = result.getDecryptionMetadata();
Assert.assertEquals(base + ": filesize must be correct", Assert.assertEquals(base + ": filesize must be correct",
@@ -168,11 +160,10 @@ public class InteropTest {
private void runImportTest(JSONObject config, File base) throws Exception { private void runImportTest(JSONObject config, File base) throws Exception {
File root = base.getParentFile(); File root = base.getParentFile();
String baseName = getBaseName(base); String baseName = getBaseName(base);
CanonicalizedKeyRing pkr = CanonicalizedKeyRing pkr = readRingFromFile(new File(root, baseName + ".asc"));
readRingFromFile(new File(root, baseName + ".asc"));
// Check we have the correct uids. // Check we have the correct uids.
ArrayList<String> expected = new ArrayList<String>(); ArrayList<String> expected = new ArrayList<>();
JSONArray uids = config.getJSONArray("expected_uids"); JSONArray uids = config.getJSONArray("expected_uids");
for (int i = 0; i < uids.length(); i++) { for (int i = 0; i < uids.length(); i++) {
expected.add(uids.getString(i)); expected.add(uids.getString(i));
@@ -188,7 +179,7 @@ public class InteropTest {
expected.add(subkeys.getJSONObject(i).getString("expected_fingerprint")); expected.add(subkeys.getJSONObject(i).getString("expected_fingerprint"));
} }
} }
ArrayList<String> actual = new ArrayList<String>(); ArrayList<String> actual = new ArrayList<>();
for (CanonicalizedPublicKey pk: pkr.publicKeyIterator()) { for (CanonicalizedPublicKey pk: pkr.publicKeyIterator()) {
if (pk.isValid()) { if (pk.isValid()) {
actual.add(KeyFormattingUtils.convertFingerprintToHex(pk.getFingerprint())); actual.add(KeyFormattingUtils.convertFingerprintToHex(pk.getFingerprint()));
@@ -204,7 +195,7 @@ public class InteropTest {
} }
} }
UncachedKeyRing readUncachedRingFromFile(File path) throws Exception { private UncachedKeyRing readUncachedRingFromFile(File path) throws Exception {
BufferedInputStream bin = null; BufferedInputStream bin = null;
try { try {
bin = new BufferedInputStream(new FileInputStream(path)); bin = new BufferedInputStream(new FileInputStream(path));
@@ -214,87 +205,40 @@ public class InteropTest {
} }
} }
CanonicalizedKeyRing readRingFromFile(File path) throws Exception { private CanonicalizedKeyRing readRingFromFile(File path) throws Exception {
UncachedKeyRing ukr = readUncachedRingFromFile(path); UncachedKeyRing ukr = readUncachedRingFromFile(path);
OperationLog log = new OperationLog(); OperationLog log = new OperationLog();
return ukr.canonicalize(log, 0); return ukr.canonicalize(log, 0);
} }
private static final void close(Closeable v) { private static void close(Closeable v) {
if (v != null) { if (v != null) {
try { try {
v.close(); v.close();
} catch (Throwable any) { } catch (Throwable ignored) {
} }
} }
} }
private static final String getBaseName(File base) { private static String getBaseName(File base) {
String name = base.getName(); String name = base.getName();
return name.substring(0, name.length() - ".json".length()); return name.substring(0, name.length() - ".json".length());
} }
private PgpDecryptVerifyOperation makeOperation(final String msg, final Passphrase passphrase, private PgpDecryptVerifyOperation makeOperation(final String msg, final Passphrase passphrase,
final CanonicalizedSecretKeyRing decrypt, final CanonicalizedPublicKeyRing verify) UncachedKeyRing decrypt, UncachedKeyRing verify) {
throws Exception { KeyWritableRepository keyRepository = KeyWritableRepository.create(RuntimeEnvironment.application);
final long decryptId = decrypt.getEncryptId(); Assert.assertTrue(keyRepository.saveSecretKeyRing(decrypt).success());
final Uri decryptUri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(decryptId); if (verify != null) {
final Uri verifyUri = verify != null ? Assert.assertTrue(keyRepository.savePublicKeyRing(verify).success());
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(verify.getMasterKeyId()) : null; }
KeyWritableRepository helper = new KeyWritableRepository(RuntimeEnvironment.application,
KeychainDatabase.getInstance(RuntimeEnvironment.application),
LocalPublicKeyStorage.getInstance(RuntimeEnvironment.application),
LocalSecretKeyStorage.getInstance(RuntimeEnvironment.application),
DatabaseNotifyManager.create(RuntimeEnvironment.application),
AutocryptPeerDao.getInstance(RuntimeEnvironment.application)) {
return new PgpDecryptVerifyOperation(RuntimeEnvironment.application, keyRepository, null) {
@Override @Override
public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws PgpKeyNotFoundException { public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId) {
Assert.assertEquals(msg + ": query should be for the decryption key", queryUri, decryptUri);
return new CachedPublicKeyRing(this, queryUri) {
@Override
public long getMasterKeyId() throws PgpKeyNotFoundException {
return decrypt.getMasterKeyId();
}
@Override
public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException {
return decrypt.getSecretKey(keyId).getSecretKeyTypeSuperExpensive();
}
};
}
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(Uri q)
throws NotFoundException {
Assert.assertEquals(msg + ": query should be for verification key", q, verifyUri);
return verify;
}
public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(Uri q)
throws NotFoundException {
Assert.assertEquals(msg + ": query should be for the decryption key", q, decryptUri);
return decrypt;
}
@Override
public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long masterKeyId)
throws NotFoundException {
Assert.assertEquals(msg + ": query should be for the decryption key",
masterKeyId, decrypt.getMasterKeyId());
return decrypt;
}
};
return new PgpDecryptVerifyOperation(RuntimeEnvironment.application, helper, null) {
@Override
public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId)
throws NoSecretKeyException {
Assert.assertEquals(msg + ": passphrase should be for the secret key", Assert.assertEquals(msg + ": passphrase should be for the secret key",
masterKeyId, decrypt.getMasterKeyId()); masterKeyId, decrypt.getMasterKeyId());
Assert.assertEquals(msg + ": passphrase should refer to the decryption subkey",
subKeyId, decryptId);
return passphrase; return passphrase;
} }
}; };

View File

@@ -18,6 +18,10 @@
package org.sufficientlysecure.keychain.provider; package org.sufficientlysecure.keychain.provider;
import java.util.Arrays;
import java.util.Iterator;
import org.bouncycastle.bcpg.sig.KeyFlags; import org.bouncycastle.bcpg.sig.KeyFlags;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
import org.junit.Assert; import org.junit.Assert;
@@ -36,9 +40,6 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import java.util.Arrays;
import java.util.Iterator;
@RunWith(KeychainTestRunner.class) @RunWith(KeychainTestRunner.class)
public class KeyRepositorySaveTest { public class KeyRepositorySaveTest {
@@ -153,9 +154,8 @@ public class KeyRepositorySaveTest {
Assert.assertTrue("canCertify() should be true", key.canCertify()); Assert.assertTrue("canCertify() should be true", key.canCertify());
Assert.assertTrue("canSign() should be true", key.canSign()); Assert.assertTrue("canSign() should be true", key.canSign());
// cached
Assert.assertEquals("all subkeys from CachedPublicKeyRing should be divert-to-key", Assert.assertEquals("all subkeys from CachedPublicKeyRing should be divert-to-key",
SecretKeyType.DIVERT_TO_CARD, cachedRing.getSecretKeyType(key.getKeyId())); SecretKeyType.DIVERT_TO_CARD, mDatabaseInteractor.getSecretKeyType(key.getKeyId()));
} }
{ // second subkey { // second subkey
@@ -169,7 +169,7 @@ public class KeyRepositorySaveTest {
// cached // cached
Assert.assertEquals("all subkeys from CachedPublicKeyRing should be divert-to-key", Assert.assertEquals("all subkeys from CachedPublicKeyRing should be divert-to-key",
SecretKeyType.DIVERT_TO_CARD, cachedRing.getSecretKeyType(key.getKeyId())); SecretKeyType.DIVERT_TO_CARD, mDatabaseInteractor.getSecretKeyType(key.getKeyId()));
} }
{ // third subkey { // third subkey
@@ -183,7 +183,7 @@ public class KeyRepositorySaveTest {
// cached // cached
Assert.assertEquals("all subkeys from CachedPublicKeyRing should be divert-to-key", Assert.assertEquals("all subkeys from CachedPublicKeyRing should be divert-to-key",
SecretKeyType.DIVERT_TO_CARD, cachedRing.getSecretKeyType(key.getKeyId())); SecretKeyType.DIVERT_TO_CARD, mDatabaseInteractor.getSecretKeyType(key.getKeyId()));
} }
Assert.assertFalse("keyring should have 3 subkeys (4)", it.hasNext()); Assert.assertFalse("keyring should have 3 subkeys (4)", it.hasNext());
@@ -233,14 +233,14 @@ public class KeyRepositorySaveTest {
Assert.assertTrue("master key should have sign flag", ring.getPublicKey().canSign()); Assert.assertTrue("master key should have sign flag", ring.getPublicKey().canSign());
Assert.assertTrue("master key should have encrypt flag", ring.getPublicKey().canEncrypt()); Assert.assertTrue("master key should have encrypt flag", ring.getPublicKey().canEncrypt());
signId = mDatabaseInteractor.getCachedPublicKeyRing(masterKeyId).getSecretSignId(); signId = mDatabaseInteractor.getSecretSignId(masterKeyId);
Assert.assertNotEquals("encrypt id should not be 0", 0, signId); Assert.assertNotEquals("encrypt id should not be 0", 0, signId);
Assert.assertNotEquals("encrypt key should be different from master key", masterKeyId, signId); Assert.assertNotEquals("signing key should be different from master key", masterKeyId, signId);
} }
{ {
CachedPublicKeyRing ring = mDatabaseInteractor.getCachedPublicKeyRing(masterKeyId); Assert.assertEquals("signing key should be same id cached as uncached",
Assert.assertEquals("signing key should be same id cached as uncached", signId, ring.getSecretSignId()); signId, mDatabaseInteractor.getSecretSignId(masterKeyId));
} }
} }

View File

@@ -76,7 +76,7 @@ public class SshPublicKeyTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application); KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingEcDsa.getMasterKeyId(); long masterKeyId = mStaticRingEcDsa.getMasterKeyId();
long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId(); long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
CanonicalizedPublicKey canonicalizedPublicKey = keyRepository.getCanonicalizedPublicKeyRing(masterKeyId) CanonicalizedPublicKey canonicalizedPublicKey = keyRepository.getCanonicalizedPublicKeyRing(masterKeyId)
.getPublicKey(authSubKeyId); .getPublicKey(authSubKeyId);