token-import: add logging

This commit is contained in:
Vincent Breitmoser 2017-09-05 05:15:21 +02:00
parent 050aed1ef5
commit 363551723b
6 changed files with 253 additions and 41 deletions

View file

@ -0,0 +1,25 @@
package org.sufficientlysecure.keychain.operations.results;
import android.os.Parcel;
public class GenericOperationResult extends OperationResult {
public GenericOperationResult(int result, OperationLog log) {
super(result, log);
}
public GenericOperationResult(Parcel source) {
super(source);
}
public static final Creator<GenericOperationResult> CREATOR = new Creator<GenericOperationResult>() {
public GenericOperationResult createFromParcel(final Parcel source) {
return new GenericOperationResult(source);
}
public GenericOperationResult[] newArray(final int size) {
return new GenericOperationResult[size];
}
};
}

View file

@ -905,6 +905,36 @@ public abstract class OperationResult implements Parcelable {
MSG_BENCH_S2K_100MS_ITS (LogLevel.INFO, R.string.msg_bench_s2k_100ms_its),
MSG_BENCH_SUCCESS (LogLevel.OK, R.string.msg_bench_success),
MSG_RET_CURI_ERROR_IO (LogLevel.ERROR, R.string.msg_ret_curi_error_io),
MSG_RET_CURI_ERROR_NO_MATCH (LogLevel.ERROR, R.string.msg_ret_curi_error_no_match),
MSG_RET_CURI_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_ret_curi_error_not_found),
MSG_RET_CURI_FOUND (LogLevel.DEBUG, R.string.msg_ret_curi_found),
MSG_RET_CURI_MISMATCH (LogLevel.ERROR, R.string.msg_ret_curi_mismatch),
MSG_RET_CURI_OK (LogLevel.OK, R.string.msg_ret_curi_ok),
MSG_RET_CURI_OPEN (LogLevel.DEBUG, R.string.msg_ret_curi_open),
MSG_RET_CURI_START (LogLevel.START, R.string.msg_ret_curi_start),
MSG_RET_KS_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_ret_ks_error_not_found),
MSG_RET_KS_ERROR (LogLevel.ERROR, R.string.msg_ret_ks_error),
MSG_RET_KS_FP_MATCH (LogLevel.DEBUG, R.string.msg_ret_ks_fp_match),
MSG_RET_KS_FP_MISMATCH (LogLevel.ERROR, R.string.msg_ret_ks_fp_mismatch),
MSG_RET_KS_OK (LogLevel.OK, R.string.msg_ret_ks_ok),
MSG_RET_KS_START (LogLevel.START, R.string.msg_ret_ks_start),
MSG_RET_LOCAL_SEARCH(LogLevel.DEBUG, R.string.msg_ret_local_search),
MSG_RET_LOCAL_FP_MATCH (LogLevel.DEBUG, R.string.msg_ret_local_fp_match),
MSG_RET_LOCAL_FP_MISMATCH (LogLevel.ERROR, R.string.msg_ret_local_fp_mismatch),
MSG_RET_LOCAL_NOT_FOUND (LogLevel.ERROR, R.string.msg_ret_local_not_found),
MSG_RET_LOCAL_OK (LogLevel.OK, R.string.msg_ret_local_ok),
MSG_RET_LOCAL_SECRET (LogLevel.INFO, R.string.msg_ret_local_secret),
MSG_RET_LOCAL_START (LogLevel.START, R.string.msg_ret_local_start),
MSG_RET_URI_ERROR_NO_MATCH(LogLevel.ERROR, R.string.msg_ret_uri_error_no_match),
MSG_RET_URI_ERROR_FETCH (LogLevel.ERROR, R.string.msg_ret_uri_error_fetch),
MSG_RET_URI_ERROR_PARSE (LogLevel.ERROR, R.string.msg_ret_uri_error_parse),
MSG_RET_URI_FETCHING (LogLevel.DEBUG, R.string.msg_ret_uri_fetching),
MSG_RET_URI_OK (LogLevel.OK, R.string.msg_ret_uri_ok),
MSG_RET_URI_START (LogLevel.START, R.string.msg_ret_uri_start),
MSG_RET_URI_NULL (LogLevel.ERROR, R.string.msg_ret_uri_null),
MSG_RET_URI_TEST (LogLevel.DEBUG, R.string.msg_ret_uri_test),
;
public final int mMsgId;

View file

@ -30,6 +30,7 @@ import android.support.v7.app.AlertDialog.Builder;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@ -39,6 +40,7 @@ import org.bouncycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
@ -137,6 +139,19 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
inflater.inflate(R.menu.token_setup, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.view_log: {
presenter.onClickViewLog();
return true;
}
default: {
return super.onOptionsItemSelected(item);
}
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -267,6 +282,13 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
}).show();
}
@Override
public void showDisplayLogActivity(OperationResult result) {
Intent intent = new Intent(getActivity(), LogDisplayActivity.class);
intent.putExtra(LogDisplayFragment.EXTRA_RESULT, result);
startActivity(intent);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
@ -327,13 +349,13 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
@Override
public void onCryptoOperationSuccess(ImportKeyResult result) {
currentImportKeyringParcel = null;
presenter.onImportSuccess();
presenter.onImportSuccess(result);
}
@Override
public void onCryptoOperationError(ImportKeyResult result) {
currentImportKeyringParcel = null;
presenter.onImportError();
presenter.onImportError(result);
}
}, null);
@ -347,13 +369,13 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
@Override
public void onCryptoOperationSuccess(PromoteKeyResult result) {
currentPromoteKeyringParcel = null;
presenter.onPromoteSuccess();
presenter.onPromoteSuccess(result);
}
@Override
public void onCryptoOperationError(PromoteKeyResult result) {
currentPromoteKeyringParcel = null;
presenter.onPromoteError();
presenter.onPromoteError(result);
}
}, null);

View file

@ -25,6 +25,9 @@ import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import org.sufficientlysecure.keychain.operations.results.GenericOperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.ui.CreateSecurityTokenImportFragment.StatusLine;
import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.ContentUriRetrievalLoader;
import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.KeyRetrievalResult;
@ -57,6 +60,7 @@ class CreateSecurityTokenImportPresenter {
private byte[] importKeyData;
private Long masterKeyId;
private OperationLog log;
CreateSecurityTokenImportPresenter(Context context, byte[] tokenFingerprints, byte[] tokenAid,
String tokenUserId, String tokenUrl, LoaderManager loaderManager) {
@ -75,6 +79,8 @@ class CreateSecurityTokenImportPresenter {
this.tokenFingerprints[i] = new byte[20];
System.arraycopy(tokenFingerprints, i*20, this.tokenFingerprints[i], 0, 20);
}
this.log = new OperationLog();
}
public void setView(CreateSecurityTokenImportMvpView view) {
@ -153,6 +159,8 @@ class CreateSecurityTokenImportPresenter {
}
}
log.add(data.getOperationResult(), 0);
if (data.isSuccess()) {
processResult(data);
} else {
@ -194,22 +202,30 @@ class CreateSecurityTokenImportPresenter {
view.operationImportKey(importKeyData);
}
void onImportSuccess() {
void onImportSuccess(OperationResult result) {
log.add(result, 0);
view.statusLineOk();
view.statusLineAdd(StatusLine.TOKEN_PROMOTE);
view.operationPromote(masterKeyId, tokenAid);
}
void onImportError() {
void onImportError(OperationResult result) {
log.add(result, 0);
view.statusLineError();
}
void onPromoteSuccess() {
void onPromoteSuccess(OperationResult result) {
log.add(result, 0);
view.statusLineOk();
view.showActionViewKey();
}
void onPromoteError() {
void onPromoteError(OperationResult result) {
log.add(result, 0);
view.statusLineError();
}
@ -252,6 +268,11 @@ class CreateSecurityTokenImportPresenter {
loaderManager.restartLoader(LOADER_CONTENT_URI, args, loaderCallbacks);
}
void onClickViewLog() {
OperationResult result = new GenericOperationResult(GenericOperationResult.RESULT_OK, log);
view.showDisplayLogActivity(result);
}
interface CreateSecurityTokenImportMvpView {
void statusLineAdd(StatusLine statusLine);
void statusLineOk();
@ -271,5 +292,7 @@ class CreateSecurityTokenImportPresenter {
void showFileSelectDialog();
void showConfirmResetDialog();
void showDisplayLogActivity(OperationResult result);
}
}

View file

@ -33,16 +33,22 @@ 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;
import org.sufficientlysecure.keychain.keyimport.KeyserverClient.QueryNotFoundException;
import org.sufficientlysecure.keychain.network.OkHttpClientFactory;
import org.sufficientlysecure.keychain.operations.results.GenericOperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
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;
@ -94,59 +100,102 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
@Override
public KeyRetrievalResult loadInBackground() {
OperationLog log = new OperationLog();
try {
log.add(LogType.MSG_RET_LOCAL_START, 0);
// TODO check other fingerprints
long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(fingerprints[0]);
log.add(LogType.MSG_RET_LOCAL_SEARCH, 1, KeyFormattingUtils.convertKeyIdToHex(masterKeyId));
CachedPublicKeyRing cachedPublicKeyRing = keyRepository.getCachedPublicKeyRing(masterKeyId);
if (!Arrays.equals(fingerprints[0], cachedPublicKeyRing.getFingerprint())) {
log.add(LogType.MSG_RET_LOCAL_FP_MISMATCH, 1);
return KeyRetrievalResult.createWithError(log);
} else {
log.add(LogType.MSG_RET_LOCAL_FP_MATCH, 1);
}
switch (cachedPublicKeyRing.getSecretKeyType(masterKeyId)) {
case PASSPHRASE:
case PASSPHRASE_EMPTY: {
return KeyRetrievalResult.createWithMasterKeyIdAndSecretAvailable(masterKeyId);
log.add(LogType.MSG_RET_LOCAL_SECRET, 1);
log.add(LogType.MSG_RET_LOCAL_OK, 1);
return KeyRetrievalResult.createWithMasterKeyIdAndSecretAvailable(log, masterKeyId);
}
case GNU_DUMMY:
case DIVERT_TO_CARD:
case UNAVAILABLE: {
return KeyRetrievalResult.createWithMasterKeyId(masterKeyId);
log.add(LogType.MSG_RET_LOCAL_OK, 1);
return KeyRetrievalResult.createWithMasterKeyId(log, masterKeyId);
}
default: {
throw new IllegalStateException("Unhandled SecretKeyType!");
}
}
} catch (NotFoundException e) {
return KeyRetrievalResult.createWithError();
} catch (PgpKeyNotFoundException | NotFoundException e) {
log.add(LogType.MSG_RET_LOCAL_NOT_FOUND, 1);
return KeyRetrievalResult.createWithError(log);
}
}
}
public static class UriKeyRetrievalLoader extends PublicKeyRetrievalLoader {
byte[][] fingerprints;
String yubikeyUri;
String tokenUri;
public UriKeyRetrievalLoader(Context context, String yubikeyUri, byte[][] fingerprints) {
public UriKeyRetrievalLoader(Context context, String tokenUri, byte[][] fingerprints) {
super(context);
this.yubikeyUri = yubikeyUri;
this.tokenUri = tokenUri;
this.fingerprints = fingerprints;
}
@Override
public KeyRetrievalResult loadInBackground() {
OperationLog log = new OperationLog();
try {
Call call = OkHttpClientFactory.getSimpleClient().newCall(new Builder().url(yubikeyUri).build());
log.add(LogType.MSG_RET_URI_START, 0);
if (tokenUri == null) {
log.add(LogType.MSG_RET_URI_NULL, 1);
return KeyRetrievalResult.createWithError(log);
}
log.add(LogType.MSG_RET_URI_FETCHING, 1, tokenUri);
HttpUrl httpUrl = HttpUrl.parse(tokenUri);
if (httpUrl == null) {
log.add(LogType.MSG_RET_URI_ERROR_PARSE, 1);
return KeyRetrievalResult.createWithError(log);
}
Call call = OkHttpClientFactory.getSimpleClient().newCall(new Builder().url(httpUrl).build());
Response execute = call.execute();
if (execute.isSuccessful()) {
UncachedKeyRing keyRing = UncachedKeyRing.decodeFromData(execute.body().bytes());
if (!execute.isSuccessful()) {
log.add(LogType.MSG_RET_URI_ERROR_FETCH, 1);
}
IteratorWithIOThrow<UncachedKeyRing> uncachedKeyRingIterator = UncachedKeyRing.fromStream(
new BufferedInputStream(execute.body().byteStream()));
while (uncachedKeyRingIterator.hasNext()) {
UncachedKeyRing keyRing = uncachedKeyRingIterator.next();
log.add(LogType.MSG_RET_URI_TEST, 1, KeyFormattingUtils.convertKeyIdToHex(keyRing.getMasterKeyId()));
if (Arrays.equals(fingerprints[0], keyRing.getFingerprint())) {
return KeyRetrievalResult.createWithKeyringdata(keyRing.getMasterKeyId(), keyRing.getEncoded());
log.add(LogType.MSG_RET_URI_OK, 1);
return KeyRetrievalResult.createWithKeyringdata(log, keyRing.getMasterKeyId(), keyRing.getEncoded());
}
}
} catch (IOException | PgpGeneralException e) {
log.add(LogType.MSG_RET_URI_ERROR_NO_MATCH, 1);
} catch (IOException e) {
log.add(LogType.MSG_RET_URI_ERROR_FETCH, 1);
Log.e(Constants.TAG, "error retrieving key from uri", e);
}
return KeyRetrievalResult.createWithError();
return KeyRetrievalResult.createWithError(log);
}
}
@ -161,26 +210,37 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
@Override
public KeyRetrievalResult loadInBackground() {
OperationLog log = new OperationLog();
HkpKeyserverAddress preferredKeyserver = Preferences.getPreferences(getContext()).getPreferredKeyserver();
ParcelableProxy parcelableProxy = Preferences.getPreferences(getContext()).getParcelableProxy();
HkpKeyserverClient keyserverClient = HkpKeyserverClient.fromHkpKeyserverAddress(preferredKeyserver);
if (true) {
return KeyRetrievalResult.createWithError();
}
try {
String keyString =
keyserverClient.get("0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint), parcelableProxy);
log.add(LogType.MSG_RET_KS_START, 0);
String keyString = keyserverClient.get(
"0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint), parcelableProxy);
UncachedKeyRing keyRing = UncachedKeyRing.decodeFromData(keyString.getBytes());
return KeyRetrievalResult.createWithKeyringdata(keyRing.getMasterKeyId(), keyRing.getEncoded());
if (!Arrays.equals(fingerprint, keyRing.getFingerprint())) {
log.add(LogType.MSG_RET_KS_FP_MISMATCH, 1);
return KeyRetrievalResult.createWithError(log);
} else {
log.add(LogType.MSG_RET_KS_FP_MATCH, 1);
}
log.add(LogType.MSG_RET_KS_OK, 1);
return KeyRetrievalResult.createWithKeyringdata(log, keyRing.getMasterKeyId(), keyRing.getEncoded());
} catch (QueryNotFoundException e) {
log.add(LogType.MSG_RET_KS_ERROR_NOT_FOUND, 1);
} catch (QueryFailedException | IOException | PgpGeneralException e) {
log.add(LogType.MSG_RET_KS_ERROR, 1);
Log.e(Constants.TAG, "error retrieving key from keyserver", e);
}
return KeyRetrievalResult.createWithError();
return KeyRetrievalResult.createWithError(log);
}
}
@ -199,25 +259,37 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
@Override
public KeyRetrievalResult loadInBackground() {
OperationLog log = new OperationLog();
try {
log.add(LogType.MSG_RET_CURI_START, 0);
log.add(LogType.MSG_RET_CURI_OPEN, 1, uri.toString());
InputStream is = contentResolver.openInputStream(uri);
if (is == null) {
return KeyRetrievalResult.createWithError();
log.add(LogType.MSG_RET_CURI_ERROR_NOT_FOUND, 1);
return KeyRetrievalResult.createWithError(log);
}
IteratorWithIOThrow<UncachedKeyRing> uncachedKeyRingIterator = UncachedKeyRing.fromStream(
new BufferedInputStream(is));
while (uncachedKeyRingIterator.hasNext()) {
UncachedKeyRing keyRing = uncachedKeyRingIterator.next();
log.add(LogType.MSG_RET_CURI_FOUND, 1, KeyFormattingUtils.convertKeyIdToHex(keyRing.getMasterKeyId()));
if (Arrays.equals(fingerprint, keyRing.getFingerprint())) {
return KeyRetrievalResult.createWithKeyringdata(keyRing.getMasterKeyId(), keyRing.getEncoded());
log.add(LogType.MSG_RET_CURI_OK, 1);
return KeyRetrievalResult.createWithKeyringdata(log, keyRing.getMasterKeyId(), keyRing.getEncoded());
} else {
log.add(LogType.MSG_RET_CURI_MISMATCH, 1);
}
}
log.add(LogType.MSG_RET_CURI_ERROR_NO_MATCH, 1);
} catch (IOException e) {
Log.e(Constants.TAG, "error retrieving key from keyserver", e);
Log.e(Constants.TAG, "error reading keyring from file", e);
log.add(LogType.MSG_RET_CURI_ERROR_IO, 1);
}
return KeyRetrievalResult.createWithError();
return KeyRetrievalResult.createWithError(log);
}
}
@ -243,6 +315,8 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
@AutoValue
static abstract class KeyRetrievalResult {
abstract GenericOperationResult getOperationResult();
@Nullable
abstract Long getMasterKeyId();
@Nullable
@ -253,20 +327,28 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
return getMasterKeyId() != null || getKeyData() != null;
}
static KeyRetrievalResult createWithError() {
return new AutoValue_PublicKeyRetrievalLoader_KeyRetrievalResult(null, null, false);
static KeyRetrievalResult createWithError(OperationLog log) {
return new AutoValue_PublicKeyRetrievalLoader_KeyRetrievalResult(
new GenericOperationResult(GenericOperationResult.RESULT_ERROR, log),
null, null, false);
}
static KeyRetrievalResult createWithKeyringdata(long masterKeyId, byte[] keyringData) {
return new AutoValue_PublicKeyRetrievalLoader_KeyRetrievalResult(masterKeyId, keyringData, false);
static KeyRetrievalResult createWithKeyringdata(OperationLog log, long masterKeyId, byte[] keyringData) {
return new AutoValue_PublicKeyRetrievalLoader_KeyRetrievalResult(
new GenericOperationResult(GenericOperationResult.RESULT_OK, log),
masterKeyId, keyringData, false);
}
static KeyRetrievalResult createWithMasterKeyIdAndSecretAvailable(long masterKeyId) {
return new AutoValue_PublicKeyRetrievalLoader_KeyRetrievalResult(masterKeyId, null, true);
static KeyRetrievalResult createWithMasterKeyIdAndSecretAvailable(OperationLog log, long masterKeyId) {
return new AutoValue_PublicKeyRetrievalLoader_KeyRetrievalResult(
new GenericOperationResult(GenericOperationResult.RESULT_OK, log),
masterKeyId, null, true);
}
static KeyRetrievalResult createWithMasterKeyId(long masterKeyId) {
return new AutoValue_PublicKeyRetrievalLoader_KeyRetrievalResult(masterKeyId, null, false);
static KeyRetrievalResult createWithMasterKeyId(OperationLog log, long masterKeyId) {
return new AutoValue_PublicKeyRetrievalLoader_KeyRetrievalResult(
new GenericOperationResult(GenericOperationResult.RESULT_OK, log),
masterKeyId, null, false);
}
}
}

View file

@ -1938,4 +1938,34 @@
<string name="token_status_token_ok">Ready for use!</string>
<string name="token_status_view_key">View Key</string>
<string name="msg_ret_curi_error_io">"Error reading data!"</string>
<string name="msg_ret_curi_error_no_match">"No matching key found"</string>
<string name="msg_ret_curi_error_not_found">"Couldn't open file!"</string>
<string name="msg_ret_curi_found">"Found key: %s"</string>
<string name="msg_ret_curi_mismatch">"Key doesn't match"</string>
<string name="msg_ret_curi_ok">"Key found"</string>
<string name="msg_ret_curi_open">"Opening Uri: %s"</string>
<string name="msg_ret_curi_start">"Loading key from file or document…"</string>
<string name="msg_ret_ks_error">"Unknown error searching for key!"</string>
<string name="msg_ret_ks_error_not_found">"Key not found"</string>
<string name="msg_ret_ks_fp_match">"Retrieved key's fingerprint matches"</string>
<string name="msg_ret_ks_fp_mismatch">"Retrieved key's fingerprint doesn't match!"</string>
<string name="msg_ret_ks_ok">"Key found"</string>
<string name="msg_ret_ks_start">"Looking for key on keyservers…"</string>
<string name="msg_ret_local_search">"Searching for key: %s"</string>
<string name="msg_ret_local_fp_match">"Local key's fingerprint matches"</string>
<string name="msg_ret_local_fp_mismatch">"Local key's fingerprint doesn't match!"</string>
<string name="msg_ret_local_not_found">"No key found"</string>
<string name="msg_ret_local_ok">"Key found"</string>
<string name="msg_ret_local_secret">"Local key contains secret key material"</string>
<string name="msg_ret_local_start">"Looking for key in local key list…"</string>
<string name="msg_ret_uri_error_fetch">"Unknown error fetching Uri!"</string>
<string name="msg_ret_uri_error_parse">"Token Uri is malformed!"</string>
<string name="msg_ret_uri_error_no_match">"No matching key found at Uri"</string>
<string name="msg_ret_uri_fetching">"Fetching Uri: %s"</string>
<string name="msg_ret_uri_ok">"Key found"</string>
<string name="msg_ret_uri_start">"Looking for key at token Uri…"</string>
<string name="msg_ret_uri_null">"No Uri saved on Security Token"</string>
<string name="msg_ret_uri_test">"Checking if found key matches: %s"</string>
</resources>