Merge pull request #1835 from nmikhailov/check_security_token
Check security token
This commit is contained in:
@@ -47,7 +47,7 @@ import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
|
||||
import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||
|
||||
@@ -144,7 +144,7 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
|
||||
|
||||
int certifyOk = 0, certifyError = 0, uploadOk = 0, uploadError = 0;
|
||||
|
||||
NfcSignOperationsBuilder allRequiredInput = new NfcSignOperationsBuilder(
|
||||
SecurityTokenSignOperationsBuilder allRequiredInput = new SecurityTokenSignOperationsBuilder(
|
||||
cryptoInput.getSignatureTime(), masterKeyId, masterKeyId);
|
||||
|
||||
// Work through all requested certifications
|
||||
|
||||
@@ -43,7 +43,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
import org.sufficientlysecure.keychain.util.InputData;
|
||||
@@ -80,7 +80,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
|
||||
int total = inputBytes != null ? 1 : inputUris.size(), count = 0;
|
||||
ArrayList<PgpSignEncryptResult> results = new ArrayList<>();
|
||||
|
||||
NfcSignOperationsBuilder pendingInputBuilder = null;
|
||||
SecurityTokenSignOperationsBuilder pendingInputBuilder = null;
|
||||
|
||||
// if signing subkey has not explicitly been set, get first usable subkey capable of signing
|
||||
if (input.getSignatureMasterKeyId() != Constants.key.none
|
||||
@@ -161,7 +161,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
|
||||
return new SignEncryptResult(log, requiredInput, results, cryptoInput);
|
||||
}
|
||||
if (pendingInputBuilder == null) {
|
||||
pendingInputBuilder = new NfcSignOperationsBuilder(requiredInput.mSignatureTime,
|
||||
pendingInputBuilder = new SecurityTokenSignOperationsBuilder(requiredInput.mSignatureTime,
|
||||
input.getSignatureMasterKeyId(), input.getSignatureSubKeyId());
|
||||
}
|
||||
pendingInputBuilder.addAll(requiredInput);
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogTyp
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
@@ -76,7 +76,7 @@ public class PgpCertifyOperation {
|
||||
// get the master subkey (which we certify for)
|
||||
PGPPublicKey publicKey = publicRing.getPublicKey().getPublicKey();
|
||||
|
||||
NfcSignOperationsBuilder requiredInput = new NfcSignOperationsBuilder(creationTimestamp,
|
||||
SecurityTokenSignOperationsBuilder requiredInput = new SecurityTokenSignOperationsBuilder(creationTimestamp,
|
||||
publicKey.getKeyID(), publicKey.getKeyID());
|
||||
|
||||
try {
|
||||
|
||||
@@ -769,7 +769,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
|
||||
&& !decryptorFactory.hasCachedSessionData(encryptedDataAsymmetric)) {
|
||||
|
||||
log.add(LogType.MSG_DC_PENDING_NFC, indent + 1);
|
||||
return result.with(new DecryptVerifyResult(log, RequiredInputParcel.createNfcDecryptOperation(
|
||||
return result.with(new DecryptVerifyResult(log, RequiredInputParcel.createSecurityTokenDecryptOperation(
|
||||
decryptionKey.getRing().getMasterKeyId(),
|
||||
decryptionKey.getKeyId(), encryptedDataAsymmetric.getSessionKey()[0]
|
||||
), cryptoInput));
|
||||
|
||||
@@ -78,8 +78,8 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
|
||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcKeyToCardOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenKeyToCardOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@@ -496,10 +496,10 @@ public class PgpKeyOperation {
|
||||
OperationLog log,
|
||||
int indent) {
|
||||
|
||||
NfcSignOperationsBuilder nfcSignOps = new NfcSignOperationsBuilder(
|
||||
SecurityTokenSignOperationsBuilder nfcSignOps = new SecurityTokenSignOperationsBuilder(
|
||||
cryptoInput.getSignatureTime(), masterSecretKey.getKeyID(),
|
||||
masterSecretKey.getKeyID());
|
||||
NfcKeyToCardOperationsBuilder nfcKeyToCardOps = new NfcKeyToCardOperationsBuilder(
|
||||
SecurityTokenKeyToCardOperationsBuilder nfcKeyToCardOps = new SecurityTokenKeyToCardOperationsBuilder(
|
||||
masterSecretKey.getKeyID());
|
||||
|
||||
progress(R.string.progress_modify, 0);
|
||||
@@ -1277,7 +1277,7 @@ public class PgpKeyOperation {
|
||||
PGPPublicKey masterPublicKey,
|
||||
int flags, long expiry,
|
||||
CryptoInputParcel cryptoInput,
|
||||
NfcSignOperationsBuilder nfcSignOps,
|
||||
SecurityTokenSignOperationsBuilder nfcSignOps,
|
||||
int indent, OperationLog log)
|
||||
throws PGPException, IOException, SignatureException {
|
||||
|
||||
|
||||
@@ -520,7 +520,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
|
||||
} catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) {
|
||||
// this secret key diverts to a OpenPGP card, throw exception with hash that will be signed
|
||||
log.add(LogType.MSG_PSE_PENDING_NFC, indent);
|
||||
return new PgpSignEncryptResult(log, RequiredInputParcel.createNfcSignOperation(
|
||||
return new PgpSignEncryptResult(log, RequiredInputParcel.createSecurityTokenSignOperation(
|
||||
signingKey.getRing().getMasterKeyId(), signingKey.getKeyId(),
|
||||
e.hashToSign, e.hashAlgo, cryptoInput.getSignatureTime()), cryptoInput);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ApiPendingIntentFactory {
|
||||
case SECURITY_TOKEN_MOVE_KEY_TO_CARD:
|
||||
case SECURITY_TOKEN_DECRYPT:
|
||||
case SECURITY_TOKEN_SIGN: {
|
||||
return createNfcOperationPendingIntent(data, requiredInput, cryptoInput);
|
||||
return createSecurityTokenOperationPendingIntent(data, requiredInput, cryptoInput);
|
||||
}
|
||||
|
||||
case PASSPHRASE: {
|
||||
@@ -65,7 +65,7 @@ public class ApiPendingIntentFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private PendingIntent createNfcOperationPendingIntent(Intent data, RequiredInputParcel requiredInput, CryptoInputParcel cryptoInput) {
|
||||
private PendingIntent createSecurityTokenOperationPendingIntent(Intent data, RequiredInputParcel requiredInput, CryptoInputParcel cryptoInput) {
|
||||
Intent intent = new Intent(mContext, RemoteSecurityTokenOperationActivity.class);
|
||||
// pass params through to activity that it can be returned again later to repeat pgp operation
|
||||
intent.putExtra(RemoteSecurityTokenOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.securitytoken;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.bouncycastle.bcpg.HashAlgorithmTags;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
@@ -131,13 +133,13 @@ public class SecurityTokenHelper {
|
||||
private boolean isSlotEmpty(KeyType keyType) throws IOException {
|
||||
// Note: special case: This should not happen, but happens with
|
||||
// https://github.com/FluffyKaon/OpenPGP-Card, thus for now assume true
|
||||
if (getMasterKeyFingerprint(keyType.getIdx()) == null) return true;
|
||||
if (getKeyFingerprint(keyType) == null) return true;
|
||||
|
||||
return keyMatchesFingerPrint(keyType, BLANK_FINGERPRINT);
|
||||
}
|
||||
|
||||
public boolean keyMatchesFingerPrint(KeyType keyType, byte[] fingerprint) throws IOException {
|
||||
return java.util.Arrays.equals(getMasterKeyFingerprint(keyType.getIdx()), fingerprint);
|
||||
return java.util.Arrays.equals(getKeyFingerprint(keyType), fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -723,10 +725,10 @@ public class SecurityTokenHelper {
|
||||
* Return the fingerprint from application specific data stored on tag, or
|
||||
* null if it doesn't exist.
|
||||
*
|
||||
* @param idx Index of the key to return the fingerprint from.
|
||||
* @param keyType key type
|
||||
* @return The fingerprint of the requested key, or null if not found.
|
||||
*/
|
||||
public byte[] getMasterKeyFingerprint(int idx) throws IOException {
|
||||
public byte[] getKeyFingerprint(@NonNull KeyType keyType) throws IOException {
|
||||
byte[] data = getFingerprints();
|
||||
if (data == null) {
|
||||
return null;
|
||||
@@ -735,7 +737,7 @@ public class SecurityTokenHelper {
|
||||
// return the master key fingerprint
|
||||
ByteBuffer fpbuf = ByteBuffer.wrap(data);
|
||||
byte[] fp = new byte[20];
|
||||
fpbuf.position(idx * 20);
|
||||
fpbuf.position(keyType.getIdx() * 20);
|
||||
fpbuf.get(fp, 0, 20);
|
||||
|
||||
return fp;
|
||||
|
||||
@@ -89,7 +89,7 @@ public class RequiredInputParcel implements Parcelable {
|
||||
return new RequiredInputParcel(RequiredInputType.ENABLE_ORBOT, null, null, null, 0L, 0L);
|
||||
}
|
||||
|
||||
public static RequiredInputParcel createNfcSignOperation(
|
||||
public static RequiredInputParcel createSecurityTokenSignOperation(
|
||||
long masterKeyId, long subKeyId,
|
||||
byte[] inputHash, int signAlgo, Date signatureTime) {
|
||||
return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_SIGN,
|
||||
@@ -97,13 +97,13 @@ public class RequiredInputParcel implements Parcelable {
|
||||
signatureTime, masterKeyId, subKeyId);
|
||||
}
|
||||
|
||||
public static RequiredInputParcel createNfcDecryptOperation(
|
||||
public static RequiredInputParcel createSecurityTokenDecryptOperation(
|
||||
long masterKeyId, long subKeyId, byte[] encryptedSessionKey) {
|
||||
return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_DECRYPT,
|
||||
new byte[][] { encryptedSessionKey }, null, null, masterKeyId, subKeyId);
|
||||
}
|
||||
|
||||
public static RequiredInputParcel createNfcReset() {
|
||||
public static RequiredInputParcel createSecurityTokenReset() {
|
||||
return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_RESET_CARD,
|
||||
null, null, null, null, null);
|
||||
}
|
||||
@@ -188,14 +188,14 @@ public class RequiredInputParcel implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
public static class NfcSignOperationsBuilder {
|
||||
public static class SecurityTokenSignOperationsBuilder {
|
||||
Date mSignatureTime;
|
||||
ArrayList<Integer> mSignAlgos = new ArrayList<>();
|
||||
ArrayList<byte[]> mInputHashes = new ArrayList<>();
|
||||
long mMasterKeyId;
|
||||
long mSubKeyId;
|
||||
|
||||
public NfcSignOperationsBuilder(Date signatureTime, long masterKeyId, long subKeyId) {
|
||||
public SecurityTokenSignOperationsBuilder(Date signatureTime, long masterKeyId, long subKeyId) {
|
||||
mSignatureTime = signatureTime;
|
||||
mMasterKeyId = masterKeyId;
|
||||
mSubKeyId = subKeyId;
|
||||
@@ -238,13 +238,13 @@ public class RequiredInputParcel implements Parcelable {
|
||||
|
||||
}
|
||||
|
||||
public static class NfcKeyToCardOperationsBuilder {
|
||||
public static class SecurityTokenKeyToCardOperationsBuilder {
|
||||
ArrayList<byte[]> mSubkeysToExport = new ArrayList<>();
|
||||
Long mMasterKeyId;
|
||||
byte[] mPin;
|
||||
byte[] mAdminPin;
|
||||
|
||||
public NfcKeyToCardOperationsBuilder(Long masterKeyId) {
|
||||
public SecurityTokenKeyToCardOperationsBuilder(Long masterKeyId) {
|
||||
mMasterKeyId = masterKeyId;
|
||||
}
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ public class CreateSecurityTokenImportResetFragment
|
||||
|
||||
public void resetCard() {
|
||||
Intent intent = new Intent(getActivity(), SecurityTokenOperationActivity.class);
|
||||
RequiredInputParcel resetP = RequiredInputParcel.createNfcReset();
|
||||
RequiredInputParcel resetP = RequiredInputParcel.createSecurityTokenReset();
|
||||
intent.putExtra(SecurityTokenOperationActivity.EXTRA_REQUIRED_INPUT, resetP);
|
||||
intent.putExtra(SecurityTokenOperationActivity.EXTRA_CRYPTO_INPUT, new CryptoInputParcel());
|
||||
startActivityForResult(intent, REQUEST_CODE_RESET);
|
||||
|
||||
@@ -36,10 +36,12 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.securitytoken.KeyType;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenNfcActivity;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.OrientationUtils;
|
||||
@@ -183,6 +185,13 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
|
||||
|
||||
switch (mRequiredInput.mType) {
|
||||
case SECURITY_TOKEN_DECRYPT: {
|
||||
long tokenKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(
|
||||
mSecurityTokenHelper.getKeyFingerprint(KeyType.ENCRYPT));
|
||||
|
||||
if (tokenKeyId != mRequiredInput.getSubKeyId()) {
|
||||
throw new IOException(getString(R.string.error_wrong_security_token));
|
||||
}
|
||||
|
||||
for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
|
||||
byte[] encryptedSessionKey = mRequiredInput.mInputData[i];
|
||||
byte[] decryptedSessionKey = mSecurityTokenHelper.decryptSessionKey(encryptedSessionKey);
|
||||
@@ -191,6 +200,13 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
|
||||
break;
|
||||
}
|
||||
case SECURITY_TOKEN_SIGN: {
|
||||
long tokenKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(
|
||||
mSecurityTokenHelper.getKeyFingerprint(KeyType.SIGN));
|
||||
|
||||
if (tokenKeyId != mRequiredInput.getSubKeyId()) {
|
||||
throw new IOException(getString(R.string.error_wrong_security_token));
|
||||
}
|
||||
|
||||
mInputParcel.addSignatureTime(mRequiredInput.mSignatureTime);
|
||||
|
||||
for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
|
||||
|
||||
@@ -380,6 +380,7 @@
|
||||
<string name="error_integrity_check_failed">"integrity check failed! Data has been modified!"</string>
|
||||
<string name="error_wrong_passphrase">"wrong password"</string>
|
||||
<string name="error_could_not_extract_private_key">"could not extract private key"</string>
|
||||
<string name="error_wrong_security_token">"this security token doesn't contain required key"</string>
|
||||
|
||||
<!-- errors without preceeding Error: -->
|
||||
<string name="error_jelly_bean_needed">"You need Android 4.1 to use Android's NFC Beam feature!"</string>
|
||||
|
||||
Reference in New Issue
Block a user