extract database access from CachedPublicKeyRing

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS certs(
rank INTEGER NOT NULL,
key_id_certifier 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,
data BLOB NOT NULL,
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_authenticate 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,
creation INTEGER NOT NULL,
expiry INTEGER,
@ -25,11 +25,12 @@ CREATE TABLE IF NOT EXISTS keys (
unifiedKeyView:
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 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,
(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_encrypt != 0 LIMIT 1) 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(user_packets.user_id, '|||') AS user_id_list
FROM keys
@ -47,6 +48,10 @@ selectUnifiedKeyInfoByMasterKeyId:
SELECT * FROM unifiedKeyView
WHERE is_revoked = 0 AND master_key_id = ?;
selectUnifiedKeyInfoByMasterKeyIds:
SELECT * FROM unifiedKeyView
WHERE is_revoked = 0 AND master_key_id IN ?;
selectUnifiedKeyInfoSearchMailAddress:
SELECT * FROM unifiedKeyView
WHERE email LIKE ?
@ -73,7 +78,19 @@ SELECT has_secret
FROM keys
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
selectMasterKeyIdsBySigner:
SELECT master_key_id
FROM key_signatures WHERE signer_key_id IN ?;
FROM key_signatures WHERE signer_key_id IN ?;

View file

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

View file

@ -19,6 +19,13 @@
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.jcajce.provider.asymmetric.eddsa.EdDSAEngine;
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.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)
public class AuthenticationOperationTest {
@ -160,7 +160,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingRsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId();
Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,
@ -206,7 +206,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingEcDsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId();
Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,
@ -252,7 +252,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingEdDsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId();
Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,
@ -300,7 +300,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingDsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId();
Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,
@ -345,7 +345,7 @@ public class AuthenticationOperationTest {
KeyRepository keyRepository = KeyRepository.create(RuntimeEnvironment.application);
long masterKeyId = mStaticRingEcDsa.getMasterKeyId();
Long authSubKeyId = keyRepository.getCachedPublicKeyRing(masterKeyId).getSecretAuthenticationId();
Long authSubKeyId = keyRepository.getSecretAuthenticationId(masterKeyId);
{ // sign challenge - should succeed with selected key allowed
AuthenticationOperation op = new AuthenticationOperation(RuntimeEnvironment.application,

View file

@ -162,15 +162,6 @@ public class BackupOperationTest {
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 =
UncachedKeyRing.fromStream(new ByteArrayInputStream(out.toByteArray()));
@ -178,7 +169,7 @@ public class BackupOperationTest {
assertTrue("export must have two keys (1/2)", unc.hasNext());
UncachedKeyRing ring = unc.next();
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("there must be no local signatures in an exported keyring",
checkForLocal(ring));
@ -188,7 +179,7 @@ public class BackupOperationTest {
assertTrue("export must have two keys (2/2)", unc.hasNext());
UncachedKeyRing ring = unc.next();
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("there must be no local signatures in an exported keyring",
checkForLocal(ring));
@ -205,7 +196,7 @@ public class BackupOperationTest {
assertTrue("export must have four keys (1/4)", unc.hasNext());
UncachedKeyRing ring = unc.next();
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("there must be no local signatures in an exported keyring",
checkForLocal(ring));
@ -213,7 +204,7 @@ public class BackupOperationTest {
assertTrue("export must have four keys (2/4)", unc.hasNext());
ring = unc.next();
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());
assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring));
@ -223,7 +214,7 @@ public class BackupOperationTest {
assertTrue("export must have four keys (3/4)", unc.hasNext());
UncachedKeyRing ring = unc.next();
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("there must be no local signatures in an exported keyring",
checkForLocal(ring));
@ -231,7 +222,7 @@ public class BackupOperationTest {
assertTrue("export must have four keys (4/4)", unc.hasNext());
ring = unc.next();
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());
assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring));

View file

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

View file

@ -105,8 +105,9 @@ public class PromoteKeyOperationTest {
@Test
public void testPromote() throws Exception {
KeyWritableRepository keyRepository = KeyWritableRepository.create(RuntimeEnvironment.application);
PromoteKeyOperation op = new PromoteKeyOperation(RuntimeEnvironment.application,
KeyWritableRepository.create(RuntimeEnvironment.application), null, null);
keyRepository, null, null);
PromoteKeyResult result = op.execute(
PromoteKeyringParcel.createPromoteKeyringParcel(mStaticRing.getMasterKeyId(), null, null), null);
@ -114,15 +115,14 @@ public class PromoteKeyOperationTest {
Assert.assertTrue("promotion must succeed", result.success());
{
CachedPublicKeyRing ring = KeyWritableRepository.create(RuntimeEnvironment.application)
.getCachedPublicKeyRing(mStaticRing.getMasterKeyId());
CachedPublicKeyRing ring = keyRepository.getCachedPublicKeyRing(mStaticRing.getMasterKeyId());
Assert.assertTrue("key must have a secret now", ring.hasAnySecret());
Iterator<UncachedPublicKey> it = mStaticRing.getPublicKeys();
while (it.hasNext()) {
long keyId = it.next().getKeyId();
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.sig.KeyFlags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
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.MissingMdc;
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.SubkeyChange;
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.OperationLog;
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.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
@ -672,7 +673,7 @@ public class PgpKeyOperationTest {
resetBuilder();
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();
Assert.assertNull("revoking a nonexistent subkey should fail", otherModified);
@ -869,7 +870,7 @@ public class PgpKeyOperationTest {
securityTokenBuilder.addOrReplaceSubkeyChange(SubkeyChange.createMoveToSecurityTokenChange(keyId));
CanonicalizedSecretKeyRing secretRing =
new CanonicalizedSecretKeyRing(ringSecurityToken.getEncoded(), 0);
new CanonicalizedSecretKeyRing(ringSecurityToken.getEncoded(), VerificationStatus.UNVERIFIED);
PgpKeyOperation op = new PgpKeyOperation(null);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, securityTokenBuilder.build());
Assert.assertTrue("moveKeyToSecurityToken operation should be pending", result.isPending());
@ -904,7 +905,7 @@ public class PgpKeyOperationTest {
securityTokenBuilder.addOrReplaceSubkeyChange(SubkeyChange.createRecertifyChange(keyId, true));
CanonicalizedSecretKeyRing secretRing =
new CanonicalizedSecretKeyRing(modified.getEncoded(), 0);
new CanonicalizedSecretKeyRing(modified.getEncoded(), VerificationStatus.UNVERIFIED);
PgpKeyOperation op = new PgpKeyOperation(null);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, securityTokenBuilder.build());
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
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());
Assert.assertTrue("key modification must succeed", result.success());
Assert.assertFalse("log must not contain a warning",
@ -1201,7 +1202,7 @@ public class PgpKeyOperationTest {
modified = KeyringTestingHelper.injectPacket(modified, sKeyWithPassphrase.buf, sKeyWithPassphrase.position);
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,
CryptoInputParcel.createCryptoInputParcel(otherPassphrase2), builder.build());
Assert.assertTrue("key modification must succeed", result.success());
@ -1214,7 +1215,7 @@ public class PgpKeyOperationTest {
@Test
public void testRestricted() throws Exception {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), 0);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), VerificationStatus.UNVERIFIED);
builder.addUserId("discord");
PgpKeyOperation op = new PgpKeyOperation(null);
@ -1250,7 +1251,7 @@ public class PgpKeyOperationTest {
try {
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);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
@ -1323,7 +1324,7 @@ public class PgpKeyOperationTest {
SaveKeyringParcel parcel, CryptoInputParcel cryptoInput, LogType expected)
throws Exception {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), 0);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), VerificationStatus.UNVERIFIED);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
Assert.assertFalse(reason, result.success());
@ -1337,7 +1338,7 @@ public class PgpKeyOperationTest {
LogType expected)
throws Exception {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), 0);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), VerificationStatus.UNVERIFIED);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
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.OperationLog;
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.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
@ -188,7 +189,7 @@ public class UncachedKeyringMergeTest {
UncachedKeyRing modifiedA, modifiedB; {
CanonicalizedSecretKeyRing secretRing =
new CanonicalizedSecretKeyRing(ringA.getEncoded(), 0);
new CanonicalizedSecretKeyRing(ringA.getEncoded(), VerificationStatus.UNVERIFIED);
resetBuilder();
builder.addUserId("flim");
@ -230,7 +231,7 @@ public class UncachedKeyringMergeTest {
UncachedKeyRing modifiedA, modifiedB;
long subKeyIdA, subKeyIdB;
{
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ringA.getEncoded(), 0);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ringA.getEncoded(), VerificationStatus.UNVERIFIED);
resetBuilder();
builder.addSubkeyAdd(SubkeyAdd.createSubkeyAdd(
@ -278,7 +279,7 @@ public class UncachedKeyringMergeTest {
resetBuilder();
builder.addRevokeSubkey(KeyringTestingHelper.getSubkeyId(ringA, 1));
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
ringA.getEncoded(), 0);
ringA.getEncoded(), VerificationStatus.UNVERIFIED);
modified = op.modifySecretKeyRing(secretRing,
CryptoInputParcel.createCryptoInputParcel(new Date(), new Passphrase()), builder.build()).getRing();
}
@ -301,10 +302,10 @@ public class UncachedKeyringMergeTest {
final UncachedKeyRing modified; {
CanonicalizedPublicKeyRing publicRing = new CanonicalizedPublicKeyRing(
pubRing.getEncoded(), 0);
pubRing.getEncoded(), VerificationStatus.UNVERIFIED);
CanonicalizedSecretKey secretKey = new CanonicalizedSecretKeyRing(
ringB.getEncoded(), 0).getSecretKey();
ringB.getEncoded(), VerificationStatus.UNVERIFIED).getSecretKey();
secretKey.unlock(new Passphrase());
PgpCertifyOperation op = new PgpCertifyOperation();
CertifyAction action = CertifyAction.createForUserIds(
@ -379,7 +380,7 @@ public class UncachedKeyringMergeTest {
builder.addUserAttribute(uat);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
ringA.getEncoded(), 0);
ringA.getEncoded(), VerificationStatus.UNVERIFIED);
modified = op.modifySecretKeyRing(secretRing,
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.util.ArrayList;
import android.net.Uri;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.json.JSONArray;
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.pgp.CanonicalizedKeyRing;
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.PgpDecryptVerifyOperation;
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.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.InputData;
@ -62,7 +55,7 @@ import org.sufficientlysecure.keychain.util.Passphrase;
public class InteropTest {
@BeforeClass
public static void setUpOnce() throws Exception {
public static void setUpOnce() {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
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");
}
private static final byte[] asBytes(File f) throws Exception {
private static byte[] asBytes(File f) throws Exception {
FileInputStream fin = null;
try {
fin = new FileInputStream(f);
@ -123,16 +116,14 @@ public class InteropTest {
private void runDecryptTest(JSONObject config, File base) throws Exception {
File root = base.getParentFile();
String baseName = getBaseName(base);
CanonicalizedPublicKeyRing verify;
UncachedKeyRing verify;
if (config.has("verifyKey")) {
verify = (CanonicalizedPublicKeyRing)
readRingFromFile(new File(root, config.getString("verifyKey")));
verify = readUncachedRingFromFile(new File(root, config.getString("verifyKey")));
} else {
verify = null;
}
CanonicalizedSecretKeyRing decrypt = (CanonicalizedSecretKeyRing)
readRingFromFile(new File(root, config.getString("decryptKey")));
UncachedKeyRing decrypt = readUncachedRingFromFile(new File(root, config.getString("decryptKey")));
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in =
@ -154,9 +145,10 @@ public class InteropTest {
if (verify != null) {
// Certain keys are too short, so we check appropriately.
int code = result.getSignatureResult().getResult();
Assert.assertTrue(base + ": should have a signature",
(code == OpenPgpSignatureResult.RESULT_INVALID_KEY_INSECURE) ||
(code == OpenPgpSignatureResult.RESULT_VALID_KEY_UNCONFIRMED));
Assert.assertTrue(base + ": should have a signature (code: " + code + ")",
code == OpenPgpSignatureResult.RESULT_INVALID_KEY_INSECURE ||
code == OpenPgpSignatureResult.RESULT_VALID_KEY_UNCONFIRMED
|| code == OpenPgpSignatureResult.RESULT_VALID_KEY_CONFIRMED);
}
OpenPgpMetadata metadata = result.getDecryptionMetadata();
Assert.assertEquals(base + ": filesize must be correct",
@ -168,11 +160,10 @@ public class InteropTest {
private void runImportTest(JSONObject config, File base) throws Exception {
File root = base.getParentFile();
String baseName = getBaseName(base);
CanonicalizedKeyRing pkr =
readRingFromFile(new File(root, baseName + ".asc"));
CanonicalizedKeyRing pkr = readRingFromFile(new File(root, baseName + ".asc"));
// Check we have the correct uids.
ArrayList<String> expected = new ArrayList<String>();
ArrayList<String> expected = new ArrayList<>();
JSONArray uids = config.getJSONArray("expected_uids");
for (int i = 0; i < uids.length(); i++) {
expected.add(uids.getString(i));
@ -188,7 +179,7 @@ public class InteropTest {
expected.add(subkeys.getJSONObject(i).getString("expected_fingerprint"));
}
}
ArrayList<String> actual = new ArrayList<String>();
ArrayList<String> actual = new ArrayList<>();
for (CanonicalizedPublicKey pk: pkr.publicKeyIterator()) {
if (pk.isValid()) {
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;
try {
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);
OperationLog log = new OperationLog();
return ukr.canonicalize(log, 0);
}
private static final void close(Closeable v) {
private static void close(Closeable v) {
if (v != null) {
try {
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();
return name.substring(0, name.length() - ".json".length());
}
private PgpDecryptVerifyOperation makeOperation(final String msg, final Passphrase passphrase,
final CanonicalizedSecretKeyRing decrypt, final CanonicalizedPublicKeyRing verify)
throws Exception {
UncachedKeyRing decrypt, UncachedKeyRing verify) {
KeyWritableRepository keyRepository = KeyWritableRepository.create(RuntimeEnvironment.application);
final long decryptId = decrypt.getEncryptId();
final Uri decryptUri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(decryptId);
final Uri verifyUri = verify != null ?
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)) {
Assert.assertTrue(keyRepository.saveSecretKeyRing(decrypt).success());
if (verify != null) {
Assert.assertTrue(keyRepository.savePublicKeyRing(verify).success());
}
return new PgpDecryptVerifyOperation(RuntimeEnvironment.application, keyRepository, null) {
@Override
public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws PgpKeyNotFoundException {
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 {
public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId) {
Assert.assertEquals(msg + ": passphrase should be for the secret key",
masterKeyId, decrypt.getMasterKeyId());
Assert.assertEquals(msg + ": passphrase should refer to the decryption subkey",
subKeyId, decryptId);
return passphrase;
}
};

View file

@ -18,6 +18,10 @@
package org.sufficientlysecure.keychain.provider;
import java.util.Arrays;
import java.util.Iterator;
import org.bouncycastle.bcpg.sig.KeyFlags;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Assert;
@ -36,9 +40,6 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.util.IterableIterator;
import java.util.Arrays;
import java.util.Iterator;
@RunWith(KeychainTestRunner.class)
public class KeyRepositorySaveTest {
@ -153,9 +154,8 @@ public class KeyRepositorySaveTest {
Assert.assertTrue("canCertify() should be true", key.canCertify());
Assert.assertTrue("canSign() should be true", key.canSign());
// cached
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
@ -169,7 +169,7 @@ public class KeyRepositorySaveTest {
// cached
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
@ -183,7 +183,7 @@ public class KeyRepositorySaveTest {
// cached
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());
@ -233,14 +233,14 @@ public class KeyRepositorySaveTest {
Assert.assertTrue("master key should have sign flag", ring.getPublicKey().canSign());
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 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", signId, ring.getSecretSignId());
Assert.assertEquals("signing key should be same id cached as uncached",
signId, mDatabaseInteractor.getSecretSignId(masterKeyId));
}
}

View file

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