rename UseCases to TokenOps, and move to operations package

This commit is contained in:
Vincent Breitmoser
2018-01-12 18:50:45 +01:00
parent c00eb7b7f3
commit 401b90a493
15 changed files with 178 additions and 145 deletions

View File

@@ -25,7 +25,7 @@ import org.sufficientlysecure.keychain.ui.CreateSecurityTokenAlgorithmFragment;
public abstract class KeyFormat { public abstract class KeyFormat {
enum KeyFormatType { public enum KeyFormatType {
RSAKeyFormatType, RSAKeyFormatType,
ECKeyFormatType ECKeyFormatType
} }
@@ -36,7 +36,7 @@ public abstract class KeyFormat {
mKeyFormatType = keyFormatType; mKeyFormatType = keyFormatType;
} }
final KeyFormatType keyFormatType() { public final KeyFormatType keyFormatType() {
return mKeyFormatType; return mKeyFormatType;
} }

View File

@@ -22,7 +22,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
@SuppressWarnings("unused") // just expose all included data @SuppressWarnings("unused") // just expose all included data
class OpenPgpCapabilities { public class OpenPgpCapabilities {
private final static int MASK_SM = 1 << 7; private final static int MASK_SM = 1 << 7;
private final static int MASK_KEY_IMPORT = 1 << 5; private final static int MASK_KEY_IMPORT = 1 << 5;
private final static int MASK_ATTRIBUTES_CHANGABLE = 1 << 2; private final static int MASK_ATTRIBUTES_CHANGABLE = 1 << 2;
@@ -42,12 +42,12 @@ class OpenPgpCapabilities {
private byte[] mFingerprints; private byte[] mFingerprints;
private byte[] mPwStatusBytes; private byte[] mPwStatusBytes;
OpenPgpCapabilities(byte[] data) throws IOException { public OpenPgpCapabilities(byte[] data) throws IOException {
mKeyFormats = new HashMap<>(); mKeyFormats = new HashMap<>();
updateWithData(data); updateWithData(data);
} }
void updateWithData(byte[] data) throws IOException { private void updateWithData(byte[] data) throws IOException {
Iso7816TLV[] tlvs = Iso7816TLV.readList(data, true); Iso7816TLV[] tlvs = Iso7816TLV.readList(data, true);
if (tlvs.length == 1 && tlvs[0].mT == 0x6E) { if (tlvs.length == 1 && tlvs[0].mT == 0x6E) {
tlvs = ((Iso7816TLV.Iso7816CompositeTLV) tlvs[0]).mSubs; tlvs = ((Iso7816TLV.Iso7816CompositeTLV) tlvs[0]).mSubs;
@@ -142,7 +142,7 @@ class OpenPgpCapabilities {
return mHasSM; return mHasSM;
} }
boolean isAttributesChangable() { public boolean isAttributesChangable() {
return mAttriburesChangable; return mAttriburesChangable;
} }
@@ -166,7 +166,7 @@ class OpenPgpCapabilities {
return mMaxRspLen; return mMaxRspLen;
} }
KeyFormat getFormatForKeyType(KeyType keyType) { public KeyFormat getFormatForKeyType(KeyType keyType) {
return mKeyFormats.get(keyType); return mKeyFormats.get(keyType);
} }

View File

@@ -27,7 +27,7 @@ import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
class OpenPgpCommandApduFactory { public class OpenPgpCommandApduFactory {
private static final int MAX_APDU_NC = 255; private static final int MAX_APDU_NC = 255;
private static final int MAX_APDU_NC_EXT = 65535; private static final int MAX_APDU_NC_EXT = 65535;
@@ -90,66 +90,11 @@ class OpenPgpCommandApduFactory {
private static final int P1_EMPTY = 0x00; private static final int P1_EMPTY = 0x00;
private static final int P2_EMPTY = 0x00; private static final int P2_EMPTY = 0x00;
@NonNull
CommandApdu createPutDataCommand(int dataObject, byte[] data) {
return CommandApdu.create(CLA, INS_PUT_DATA, (dataObject & 0xFF00) >> 8, dataObject & 0xFF, data);
}
@NonNull
CommandApdu createPutKeyCommand(byte[] keyBytes) {
// the odd PUT DATA INS is for compliance with ISO 7816-8. This is used only to put key data on the card
return CommandApdu.create(CLA, INS_PUT_DATA_ODD, P1_PUT_DATA_ODD_KEY, P2_PUT_DATA_ODD_KEY, keyBytes);
}
@NonNull
CommandApdu createComputeDigitalSignatureCommand(byte[] data) {
return CommandApdu.create(CLA, INS_PERFORM_SECURITY_OPERATION, P1_PSO_COMPUTE_DIGITAL_SIGNATURE,
P2_PSO_COMPUTE_DIGITAL_SIGNATURE, data, MAX_APDU_NE_EXT);
}
@NonNull
CommandApdu createDecipherCommand(byte[] data) {
return CommandApdu.create(CLA, INS_PERFORM_SECURITY_OPERATION, P1_PSO_DECIPHER, P2_PSO_DECIPHER, data,
MAX_APDU_NE_EXT);
}
@NonNull
CommandApdu createChangePw3Command(byte[] adminPin, byte[] newAdminPin) {
return CommandApdu.create(CLA, INS_CHANGE_REFERENCE_DATA, P1_EMPTY,
P2_CHANGE_REFERENCE_DATA_PW3, Arrays.concatenate(adminPin, newAdminPin));
}
@NonNull
CommandApdu createResetPw1Command(byte[] newPin) {
return CommandApdu.create(CLA, INS_RESET_RETRY_COUNTER, P1_RESET_RETRY_COUNTER_NEW_PW,
P2_RESET_RETRY_COUNTER, newPin);
}
@NonNull
CommandApdu createGetDataCommand(int p1, int p2) {
return CommandApdu.create(CLA, INS_GET_DATA, p1, p2, MAX_APDU_NE_EXT);
}
@NonNull
CommandApdu createGetResponseCommand(int lastResponseSw2) {
return CommandApdu.create(CLA, INS_GET_RESPONSE, P1_EMPTY, P2_EMPTY, lastResponseSw2);
}
@NonNull
CommandApdu createVerifyPw1ForSignatureCommand(byte[] pin) {
return CommandApdu.create(CLA, INS_VERIFY, P1_EMPTY, P2_VERIFY_PW1_SIGN, pin);
}
@NonNull @NonNull
CommandApdu createVerifyPw1ForOtherCommand(byte[] pin) { CommandApdu createVerifyPw1ForOtherCommand(byte[] pin) {
return CommandApdu.create(CLA, INS_VERIFY, P1_EMPTY, P2_VERIFY_PW1_OTHER, pin); return CommandApdu.create(CLA, INS_VERIFY, P1_EMPTY, P2_VERIFY_PW1_OTHER, pin);
} }
@NonNull
CommandApdu createVerifyPw3Command(byte[] pin) {
return CommandApdu.create(CLA, INS_VERIFY, P1_EMPTY, P2_VERIFY_PW3, pin);
}
@NonNull @NonNull
CommandApdu createSelectFileOpenPgpCommand() { CommandApdu createSelectFileOpenPgpCommand() {
return CommandApdu.create(CLA, INS_SELECT_FILE, P1_SELECT_FILE, P2_EMPTY, AID_SELECT_FILE_OPENPGP); return CommandApdu.create(CLA, INS_SELECT_FILE, P1_SELECT_FILE, P2_EMPTY, AID_SELECT_FILE_OPENPGP);
@@ -161,12 +106,67 @@ class OpenPgpCommandApduFactory {
} }
@NonNull @NonNull
CommandApdu createReactivate1Command() { CommandApdu createGetDataCommand(int p1, int p2) {
return CommandApdu.create(CLA, INS_GET_DATA, p1, p2, MAX_APDU_NE_EXT);
}
@NonNull
CommandApdu createGetResponseCommand(int lastResponseSw2) {
return CommandApdu.create(CLA, INS_GET_RESPONSE, P1_EMPTY, P2_EMPTY, lastResponseSw2);
}
@NonNull
public CommandApdu createPutDataCommand(int dataObject, byte[] data) {
return CommandApdu.create(CLA, INS_PUT_DATA, (dataObject & 0xFF00) >> 8, dataObject & 0xFF, data);
}
@NonNull
public CommandApdu createPutKeyCommand(byte[] keyBytes) {
// the odd PUT DATA INS is for compliance with ISO 7816-8. This is used only to put key data on the card
return CommandApdu.create(CLA, INS_PUT_DATA_ODD, P1_PUT_DATA_ODD_KEY, P2_PUT_DATA_ODD_KEY, keyBytes);
}
@NonNull
public CommandApdu createComputeDigitalSignatureCommand(byte[] data) {
return CommandApdu.create(CLA, INS_PERFORM_SECURITY_OPERATION, P1_PSO_COMPUTE_DIGITAL_SIGNATURE,
P2_PSO_COMPUTE_DIGITAL_SIGNATURE, data, MAX_APDU_NE_EXT);
}
@NonNull
public CommandApdu createDecipherCommand(byte[] data) {
return CommandApdu.create(CLA, INS_PERFORM_SECURITY_OPERATION, P1_PSO_DECIPHER, P2_PSO_DECIPHER, data,
MAX_APDU_NE_EXT);
}
@NonNull
public CommandApdu createChangePw3Command(byte[] adminPin, byte[] newAdminPin) {
return CommandApdu.create(CLA, INS_CHANGE_REFERENCE_DATA, P1_EMPTY,
P2_CHANGE_REFERENCE_DATA_PW3, Arrays.concatenate(adminPin, newAdminPin));
}
@NonNull
public CommandApdu createResetPw1Command(byte[] newPin) {
return CommandApdu.create(CLA, INS_RESET_RETRY_COUNTER, P1_RESET_RETRY_COUNTER_NEW_PW,
P2_RESET_RETRY_COUNTER, newPin);
}
@NonNull
public CommandApdu createVerifyPw1ForSignatureCommand(byte[] pin) {
return CommandApdu.create(CLA, INS_VERIFY, P1_EMPTY, P2_VERIFY_PW1_SIGN, pin);
}
@NonNull
public CommandApdu createVerifyPw3Command(byte[] pin) {
return CommandApdu.create(CLA, INS_VERIFY, P1_EMPTY, P2_VERIFY_PW3, pin);
}
@NonNull
public CommandApdu createReactivate1Command() {
return CommandApdu.create(CLA, INS_TERMINATE_DF, P1_EMPTY, P2_EMPTY); return CommandApdu.create(CLA, INS_TERMINATE_DF, P1_EMPTY, P2_EMPTY);
} }
@NonNull @NonNull
CommandApdu createReactivate2Command() { public CommandApdu createReactivate2Command() {
return CommandApdu.create(CLA, INS_ACTIVATE_FILE, P1_EMPTY, P2_EMPTY); return CommandApdu.create(CLA, INS_ACTIVATE_FILE, P1_EMPTY, P2_EMPTY);
} }
@@ -177,12 +177,12 @@ class OpenPgpCommandApduFactory {
} }
@NonNull @NonNull
CommandApdu createInternalAuthCommand(byte[] authData) { public CommandApdu createInternalAuthCommand(byte[] authData) {
return CommandApdu.create(CLA, INS_INTERNAL_AUTHENTICATE, P1_EMPTY, P2_EMPTY, authData, MAX_APDU_NE_EXT); return CommandApdu.create(CLA, INS_INTERNAL_AUTHENTICATE, P1_EMPTY, P2_EMPTY, authData, MAX_APDU_NE_EXT);
} }
@NonNull @NonNull
CommandApdu createGenerateKeyCommand(int slot) { public CommandApdu createGenerateKeyCommand(int slot) {
return CommandApdu.create(CLA, INS_GENERATE_ASYMMETRIC_KEY_PAIR, return CommandApdu.create(CLA, INS_GENERATE_ASYMMETRIC_KEY_PAIR,
P1_GAKP_GENERATE, P2_EMPTY, new byte[] { (byte) slot, 0x00 }, MAX_APDU_NE_EXT); P1_GAKP_GENERATE, P2_EMPTY, new byte[] { (byte) slot, 0x00 }, MAX_APDU_NE_EXT);
} }

View File

@@ -152,7 +152,7 @@ public class SecurityTokenConnection {
tokenType = TokenType.UNKNOWN; tokenType = TokenType.UNKNOWN;
} }
void refreshConnectionCapabilities() throws IOException { public void refreshConnectionCapabilities() throws IOException {
byte[] rawOpenPgpCapabilities = getData(0x00, 0x6E); byte[] rawOpenPgpCapabilities = getData(0x00, 0x6E);
OpenPgpCapabilities openPgpCapabilities = new OpenPgpCapabilities(rawOpenPgpCapabilities); OpenPgpCapabilities openPgpCapabilities = new OpenPgpCapabilities(rawOpenPgpCapabilities);
@@ -177,7 +177,7 @@ public class SecurityTokenConnection {
* @param commandApdu short or extended APDU to transceive * @param commandApdu short or extended APDU to transceive
* @return response from the card * @return response from the card
*/ */
ResponseApdu communicate(CommandApdu commandApdu) throws IOException { public ResponseApdu communicate(CommandApdu commandApdu) throws IOException {
commandApdu = smEncryptIfAvailable(commandApdu); commandApdu = smEncryptIfAvailable(commandApdu);
ResponseApdu lastResponse; ResponseApdu lastResponse;
@@ -296,7 +296,7 @@ public class SecurityTokenConnection {
// region pin management // region pin management
void verifyPinForSignature() throws IOException { public void verifyPinForSignature() throws IOException {
if (isPw1ValidatedForSignature) { if (isPw1ValidatedForSignature) {
return; return;
} }
@@ -315,7 +315,7 @@ public class SecurityTokenConnection {
isPw1ValidatedForSignature = true; isPw1ValidatedForSignature = true;
} }
void verifyPinForOther() throws IOException { public void verifyPinForOther() throws IOException {
if (isPw1ValidatedForOther) { if (isPw1ValidatedForOther) {
return; return;
} }
@@ -334,7 +334,7 @@ public class SecurityTokenConnection {
isPw1ValidatedForOther = true; isPw1ValidatedForOther = true;
} }
void verifyAdminPin(Passphrase adminPin) throws IOException { public void verifyAdminPin(Passphrase adminPin) throws IOException {
if (isPw3Validated) { if (isPw3Validated) {
return; return;
} }
@@ -348,13 +348,13 @@ public class SecurityTokenConnection {
isPw3Validated = true; isPw3Validated = true;
} }
void invalidateSingleUsePw1() { public void invalidateSingleUsePw1() {
if (!openPgpCapabilities.isPw1ValidForMultipleSignatures()) { if (!openPgpCapabilities.isPw1ValidForMultipleSignatures()) {
isPw1ValidatedForSignature = false; isPw1ValidatedForSignature = false;
} }
} }
void invalidatePw3() { public void invalidatePw3() {
isPw3Validated = false; isPw3Validated = false;
} }
@@ -415,15 +415,15 @@ public class SecurityTokenConnection {
return tokenType; return tokenType;
} }
OpenPgpCapabilities getOpenPgpCapabilities() { public OpenPgpCapabilities getOpenPgpCapabilities() {
return openPgpCapabilities; return openPgpCapabilities;
} }
OpenPgpCommandApduFactory getCommandFactory() { public OpenPgpCommandApduFactory getCommandFactory() {
return commandFactory; return commandFactory;
} }
byte[] getPwStatusBytes() { public byte[] getPwStatusBytes() {
return openPgpCapabilities.getPwStatusBytes(); return openPgpCapabilities.getPwStatusBytes();
} }

View File

@@ -32,8 +32,9 @@ import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPrivateCrtKey;
class SecurityTokenUtils { public class SecurityTokenUtils {
static byte[] attributesFromSecretKey(KeyType slot, CanonicalizedSecretKey secretKey, KeyFormat formatForKeyType) public static byte[] attributesFromSecretKey(KeyType slot, CanonicalizedSecretKey secretKey,
KeyFormat formatForKeyType)
throws IOException { throws IOException {
if (secretKey.isRSA()) { if (secretKey.isRSA()) {
return attributesForRsaKey(secretKey.getBitStrength(), (RSAKeyFormat) formatForKeyType); return attributesForRsaKey(secretKey.getBitStrength(), (RSAKeyFormat) formatForKeyType);
@@ -73,7 +74,7 @@ class SecurityTokenUtils {
return attrs; return attrs;
} }
static byte[] createRSAPrivKeyTemplate(RSAPrivateCrtKey secretKey, KeyType slot, public static byte[] createRSAPrivKeyTemplate(RSAPrivateCrtKey secretKey, KeyType slot,
RSAKeyFormat format) throws IOException { RSAKeyFormat format) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream(), ByteArrayOutputStream stream = new ByteArrayOutputStream(),
template = new ByteArrayOutputStream(), template = new ByteArrayOutputStream(),
@@ -141,7 +142,7 @@ class SecurityTokenUtils {
return res.toByteArray(); return res.toByteArray();
} }
static byte[] createECPrivKeyTemplate(ECPrivateKey secretKey, ECPublicKey publicKey, KeyType slot, public static byte[] createECPrivKeyTemplate(ECPrivateKey secretKey, ECPublicKey publicKey, KeyType slot,
ECKeyFormat format) throws IOException { ECKeyFormat format) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream(), ByteArrayOutputStream stream = new ByteArrayOutputStream(),
template = new ByteArrayOutputStream(), template = new ByteArrayOutputStream(),

View File

@@ -1,19 +1,22 @@
package org.sufficientlysecure.keychain.securitytoken; package org.sufficientlysecure.keychain.securitytoken.operations;
import java.io.IOException; import java.io.IOException;
import org.sufficientlysecure.keychain.securitytoken.CommandApdu;
import org.sufficientlysecure.keychain.securitytoken.ResponseApdu;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
public class GenerateKeyUseCase { public class GenerateKeyTokenOp {
private final SecurityTokenConnection connection; private final SecurityTokenConnection connection;
public static GenerateKeyUseCase create(SecurityTokenConnection connection) { public static GenerateKeyTokenOp create(SecurityTokenConnection connection) {
return new GenerateKeyUseCase(connection); return new GenerateKeyTokenOp(connection);
} }
private GenerateKeyUseCase(SecurityTokenConnection connection) { private GenerateKeyTokenOp(SecurityTokenConnection connection) {
this.connection = connection; this.connection = connection;
} }

View File

@@ -1,23 +1,27 @@
package org.sufficientlysecure.keychain.securitytoken; package org.sufficientlysecure.keychain.securitytoken.operations;
import java.io.IOException; import java.io.IOException;
import org.sufficientlysecure.keychain.securitytoken.CardException;
import org.sufficientlysecure.keychain.securitytoken.CommandApdu;
import org.sufficientlysecure.keychain.securitytoken.ResponseApdu;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
public class ModifyPinUseCase { public class ModifyPinTokenOp {
private static final int MAX_PW3_LENGTH_INDEX = 3; private static final int MAX_PW3_LENGTH_INDEX = 3;
private static final int MIN_PW3_LENGTH = 8; private static final int MIN_PW3_LENGTH = 8;
private final SecurityTokenConnection connection; private final SecurityTokenConnection connection;
private final Passphrase adminPin; private final Passphrase adminPin;
public static ModifyPinUseCase create(SecurityTokenConnection connection, Passphrase adminPin) { public static ModifyPinTokenOp create(SecurityTokenConnection connection, Passphrase adminPin) {
return new ModifyPinUseCase(connection, adminPin); return new ModifyPinTokenOp(connection, adminPin);
} }
private ModifyPinUseCase(SecurityTokenConnection connection, private ModifyPinTokenOp(SecurityTokenConnection connection,
Passphrase adminPin) { Passphrase adminPin) {
this.connection = connection; this.connection = connection;
this.adminPin = adminPin; this.adminPin = adminPin;

View File

@@ -1,4 +1,4 @@
package org.sufficientlysecure.keychain.securitytoken; package org.sufficientlysecure.keychain.securitytoken.operations;
import java.io.IOException; import java.io.IOException;
@@ -22,21 +22,28 @@ import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.securitytoken.CardException;
import org.sufficientlysecure.keychain.securitytoken.CommandApdu;
import org.sufficientlysecure.keychain.securitytoken.ECKeyFormat;
import org.sufficientlysecure.keychain.securitytoken.KeyFormat;
import org.sufficientlysecure.keychain.securitytoken.KeyType;
import org.sufficientlysecure.keychain.securitytoken.ResponseApdu;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
/** This class implements the PSO:DECIPHER operation, as specified in OpenPGP card spec / 7.2.11 (p52 in v3.0.1). /** This class implements the PSO:DECIPHER operation, as specified in OpenPGP card spec / 7.2.11 (p52 in v3.0.1).
* *
* See https://www.g10code.com/docs/openpgp-card-3.0.pdf * See https://www.g10code.com/docs/openpgp-card-3.0.pdf
*/ */
public class PsoDecryptUseCase { public class PsoDecryptTokenOp {
private final SecurityTokenConnection connection; private final SecurityTokenConnection connection;
private final JcaKeyFingerprintCalculator fingerprintCalculator; private final JcaKeyFingerprintCalculator fingerprintCalculator;
public static PsoDecryptUseCase create(SecurityTokenConnection connection) { public static PsoDecryptTokenOp create(SecurityTokenConnection connection) {
return new PsoDecryptUseCase(connection, new JcaKeyFingerprintCalculator()); return new PsoDecryptTokenOp(connection, new JcaKeyFingerprintCalculator());
} }
private PsoDecryptUseCase(SecurityTokenConnection connection, private PsoDecryptTokenOp(SecurityTokenConnection connection,
JcaKeyFingerprintCalculator jcaKeyFingerprintCalculator) { JcaKeyFingerprintCalculator jcaKeyFingerprintCalculator) {
this.connection = connection; this.connection = connection;
this.fingerprintCalculator = jcaKeyFingerprintCalculator; this.fingerprintCalculator = jcaKeyFingerprintCalculator;

View File

@@ -1,17 +1,22 @@
package org.sufficientlysecure.keychain.securitytoken; package org.sufficientlysecure.keychain.securitytoken.operations;
import java.io.IOException; import java.io.IOException;
import org.sufficientlysecure.keychain.securitytoken.CardException;
import org.sufficientlysecure.keychain.securitytoken.CommandApdu;
import org.sufficientlysecure.keychain.securitytoken.ResponseApdu;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
public class ResetAndWipeUseCase {
public class ResetAndWipeTokenOp {
private final SecurityTokenConnection connection; private final SecurityTokenConnection connection;
public static ResetAndWipeUseCase create(SecurityTokenConnection connection) { public static ResetAndWipeTokenOp create(SecurityTokenConnection connection) {
return new ResetAndWipeUseCase(connection); return new ResetAndWipeTokenOp(connection);
} }
private ResetAndWipeUseCase(SecurityTokenConnection connection) { private ResetAndWipeTokenOp(SecurityTokenConnection connection) {
this.connection = connection; this.connection = connection;
} }

View File

@@ -1,4 +1,4 @@
package org.sufficientlysecure.keychain.securitytoken; package org.sufficientlysecure.keychain.securitytoken.operations;
import java.io.IOException; import java.io.IOException;
@@ -12,19 +12,29 @@ import android.support.annotation.VisibleForTesting;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.securitytoken.CardException;
import org.sufficientlysecure.keychain.securitytoken.CommandApdu;
import org.sufficientlysecure.keychain.securitytoken.ECKeyFormat;
import org.sufficientlysecure.keychain.securitytoken.KeyFormat;
import org.sufficientlysecure.keychain.securitytoken.KeyType;
import org.sufficientlysecure.keychain.securitytoken.OpenPgpCapabilities;
import org.sufficientlysecure.keychain.securitytoken.RSAKeyFormat;
import org.sufficientlysecure.keychain.securitytoken.ResponseApdu;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenUtils;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
public class SecurityTokenChangeKeyUseCase { public class SecurityTokenChangeKeyTokenOp {
private static final byte[] BLANK_FINGERPRINT = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; private static final byte[] BLANK_FINGERPRINT = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
private final SecurityTokenConnection connection; private final SecurityTokenConnection connection;
public static SecurityTokenChangeKeyUseCase create(SecurityTokenConnection stConnection) { public static SecurityTokenChangeKeyTokenOp create(SecurityTokenConnection stConnection) {
return new SecurityTokenChangeKeyUseCase(stConnection); return new SecurityTokenChangeKeyTokenOp(stConnection);
} }
private SecurityTokenChangeKeyUseCase(SecurityTokenConnection connection) { private SecurityTokenChangeKeyTokenOp(SecurityTokenConnection connection) {
this.connection = connection; this.connection = connection;
} }

View File

@@ -1,4 +1,4 @@
package org.sufficientlysecure.keychain.securitytoken; package org.sufficientlysecure.keychain.securitytoken.operations;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -12,17 +12,25 @@ import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.securitytoken.CardException;
import org.sufficientlysecure.keychain.securitytoken.CommandApdu;
import org.sufficientlysecure.keychain.securitytoken.KeyFormat;
import org.sufficientlysecure.keychain.securitytoken.KeyType;
import org.sufficientlysecure.keychain.securitytoken.OpenPgpCapabilities;
import org.sufficientlysecure.keychain.securitytoken.RSAKeyFormat;
import org.sufficientlysecure.keychain.securitytoken.ResponseApdu;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
public class SecurityTokenPsoSignUseCase { public class SecurityTokenPsoSignTokenOp {
private final SecurityTokenConnection connection; private final SecurityTokenConnection connection;
public static SecurityTokenPsoSignUseCase create(SecurityTokenConnection connection) { public static SecurityTokenPsoSignTokenOp create(SecurityTokenConnection connection) {
return new SecurityTokenPsoSignUseCase(connection); return new SecurityTokenPsoSignTokenOp(connection);
} }
private SecurityTokenPsoSignUseCase(SecurityTokenConnection connection) { private SecurityTokenPsoSignTokenOp(SecurityTokenConnection connection) {
this.connection = connection; this.connection = connection;
} }

View File

@@ -32,7 +32,7 @@ import android.widget.ViewAnimator;
import nordpol.android.NfcGuideView; import nordpol.android.NfcGuideView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.securitytoken.ModifyPinUseCase; import org.sufficientlysecure.keychain.securitytoken.operations.ModifyPinTokenOp;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo;
import org.sufficientlysecure.keychain.service.input.SecurityTokenChangePinParcel; import org.sufficientlysecure.keychain.service.input.SecurityTokenChangePinParcel;
@@ -142,7 +142,7 @@ public class SecurityTokenChangePinOperationActivity extends BaseSecurityTokenAc
@Override @Override
protected void doSecurityTokenInBackground(SecurityTokenConnection stConnection) throws IOException { protected void doSecurityTokenInBackground(SecurityTokenConnection stConnection) throws IOException {
Passphrase adminPin = new Passphrase(changePinInput.getAdminPin()); Passphrase adminPin = new Passphrase(changePinInput.getAdminPin());
ModifyPinUseCase.create(stConnection, adminPin).modifyPw1Pin(changePinInput.getNewPin().getBytes()); ModifyPinTokenOp.create(stConnection, adminPin).modifyPw1Pin(changePinInput.getNewPin().getBytes());
resultTokenInfo = stConnection.getTokenInfo(); resultTokenInfo = stConnection.getTokenInfo();
} }

View File

@@ -40,13 +40,13 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.securitytoken.KeyType; import org.sufficientlysecure.keychain.securitytoken.KeyType;
import org.sufficientlysecure.keychain.securitytoken.ModifyPinUseCase; import org.sufficientlysecure.keychain.securitytoken.operations.ModifyPinTokenOp;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo;
import org.sufficientlysecure.keychain.securitytoken.PsoDecryptUseCase; import org.sufficientlysecure.keychain.securitytoken.operations.PsoDecryptTokenOp;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenPsoSignUseCase; import org.sufficientlysecure.keychain.securitytoken.operations.SecurityTokenPsoSignTokenOp;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenChangeKeyUseCase; import org.sufficientlysecure.keychain.securitytoken.operations.SecurityTokenChangeKeyTokenOp;
import org.sufficientlysecure.keychain.securitytoken.ResetAndWipeUseCase; import org.sufficientlysecure.keychain.securitytoken.operations.ResetAndWipeTokenOp;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
@@ -210,10 +210,10 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity {
throw new IOException("Couldn't find subkey for key to token operation."); throw new IOException("Couldn't find subkey for key to token operation.");
} }
PsoDecryptUseCase psoDecryptUseCase = PsoDecryptUseCase.create(stConnection); PsoDecryptTokenOp psoDecryptTokenOp = PsoDecryptTokenOp.create(stConnection);
for (int i = 0; i < mRequiredInput.mInputData.length; i++) { for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
byte[] encryptedSessionKey = mRequiredInput.mInputData[i]; byte[] encryptedSessionKey = mRequiredInput.mInputData[i];
byte[] decryptedSessionKey = psoDecryptUseCase byte[] decryptedSessionKey = psoDecryptTokenOp
.verifyAndDecryptSessionKey(encryptedSessionKey, publicKeyRing.getPublicKey(tokenKeyId)); .verifyAndDecryptSessionKey(encryptedSessionKey, publicKeyRing.getPublicKey(tokenKeyId));
mInputParcel = mInputParcel.withCryptoData(encryptedSessionKey, decryptedSessionKey); mInputParcel = mInputParcel.withCryptoData(encryptedSessionKey, decryptedSessionKey);
} }
@@ -229,7 +229,7 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity {
mInputParcel = mInputParcel.withSignatureTime(mRequiredInput.mSignatureTime); mInputParcel = mInputParcel.withSignatureTime(mRequiredInput.mSignatureTime);
SecurityTokenPsoSignUseCase psoSignUseCase = SecurityTokenPsoSignUseCase.create(stConnection); SecurityTokenPsoSignTokenOp psoSignUseCase = SecurityTokenPsoSignTokenOp.create(stConnection);
for (int i = 0; i < mRequiredInput.mInputData.length; i++) { for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
byte[] hash = mRequiredInput.mInputData[i]; byte[] hash = mRequiredInput.mInputData[i];
int algo = mRequiredInput.mSignAlgos[i]; int algo = mRequiredInput.mSignAlgos[i];
@@ -246,7 +246,7 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity {
throw new IOException(getString(R.string.error_wrong_security_token)); throw new IOException(getString(R.string.error_wrong_security_token));
} }
SecurityTokenPsoSignUseCase psoSignUseCase = SecurityTokenPsoSignUseCase.create(stConnection); SecurityTokenPsoSignTokenOp psoSignUseCase = SecurityTokenPsoSignTokenOp.create(stConnection);
for (int i = 0; i < mRequiredInput.mInputData.length; i++) { for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
byte[] hash = mRequiredInput.mInputData[i]; byte[] hash = mRequiredInput.mInputData[i];
int algo = mRequiredInput.mSignAlgos[i]; int algo = mRequiredInput.mSignAlgos[i];
@@ -290,21 +290,21 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity {
throw new IOException("Unable to get cached passphrase!"); throw new IOException("Unable to get cached passphrase!");
} }
SecurityTokenChangeKeyUseCase putKeyUseCase = SecurityTokenChangeKeyUseCase.create(stConnection); SecurityTokenChangeKeyTokenOp putKeyUseCase = SecurityTokenChangeKeyTokenOp.create(stConnection);
putKeyUseCase.changeKey(key, passphrase, adminPin); putKeyUseCase.changeKey(key, passphrase, adminPin);
// TODO: Is this really used anywhere? // TODO: Is this really used anywhere?
mInputParcel = mInputParcel.withCryptoData(subkeyBytes, tokenSerialNumber); mInputParcel = mInputParcel.withCryptoData(subkeyBytes, tokenSerialNumber);
} }
ModifyPinUseCase.create(stConnection, adminPin).modifyPw1andPw3Pins(newPin, newAdminPin); ModifyPinTokenOp.create(stConnection, adminPin).modifyPw1andPw3Pins(newPin, newAdminPin);
SecurityTokenConnection.clearCachedConnections(); SecurityTokenConnection.clearCachedConnections();
break; break;
} }
case SECURITY_TOKEN_RESET_CARD: { case SECURITY_TOKEN_RESET_CARD: {
ResetAndWipeUseCase.create(stConnection).resetAndWipeToken(); ResetAndWipeTokenOp.create(stConnection).resetAndWipeToken();
mResultTokenInfo = stConnection.getTokenInfo(); mResultTokenInfo = stConnection.getTokenInfo();
break; break;

View File

@@ -6,6 +6,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.sufficientlysecure.keychain.KeychainTestRunner; import org.sufficientlysecure.keychain.KeychainTestRunner;
import org.sufficientlysecure.keychain.securitytoken.operations.PsoDecryptTokenOp;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
@@ -14,7 +15,7 @@ import static org.mockito.Mockito.when;
@RunWith(KeychainTestRunner.class) @RunWith(KeychainTestRunner.class)
public class PsoDecryptUseCaseTest { public class PsoDecryptTokenOpTest {
private static final byte[] RSA_ENC_SESSIONKEY_MPI = Hex.decode( private static final byte[] RSA_ENC_SESSIONKEY_MPI = Hex.decode(
"07ff7b9ff36f70da1fe7a6b59168c24a7e5b48a938c4f970de46524a06ebf4a9175a9737cf2e6f30957110b31db7" + "07ff7b9ff36f70da1fe7a6b59168c24a7e5b48a938c4f970de46524a06ebf4a9175a9737cf2e6f30957110b31db7" +
"0e9a2992401b1d5e99389f976356f4e3a28ff537362e7ce14b81200e21d4f0e77d46bd89f3a54ca06062289148a5938748" + "0e9a2992401b1d5e99389f976356f4e3a28ff537362e7ce14b81200e21d4f0e77d46bd89f3a54ca06062289148a5938748" +
@@ -24,7 +25,7 @@ public class PsoDecryptUseCaseTest {
"51265229bcbb0da5d5aeb4eafbad9779"); "51265229bcbb0da5d5aeb4eafbad9779");
private SecurityTokenConnection securityTokenConnection; private SecurityTokenConnection securityTokenConnection;
private OpenPgpCommandApduFactory commandFactory; private OpenPgpCommandApduFactory commandFactory;
private PsoDecryptUseCase useCase; private PsoDecryptTokenOp useCase;
private CommandApdu dummyCommandApdu = mock(CommandApdu.class); private CommandApdu dummyCommandApdu = mock(CommandApdu.class);
@@ -35,7 +36,7 @@ public class PsoDecryptUseCaseTest {
commandFactory = mock(OpenPgpCommandApduFactory.class); commandFactory = mock(OpenPgpCommandApduFactory.class);
when(securityTokenConnection.getCommandFactory()).thenReturn(commandFactory); when(securityTokenConnection.getCommandFactory()).thenReturn(commandFactory);
useCase = PsoDecryptUseCase.create(securityTokenConnection); useCase = PsoDecryptTokenOp.create(securityTokenConnection);
} }
@Test @Test

View File

@@ -1,31 +1,25 @@
package org.sufficientlysecure.keychain.securitytoken; package org.sufficientlysecure.keychain.securitytoken.operations;
import java.io.IOException;
import java.util.LinkedList;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.AdditionalMatchers; import org.mockito.AdditionalMatchers;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowLog; import org.robolectric.shadows.ShadowLog;
import org.sufficientlysecure.keychain.KeychainTestRunner; import org.sufficientlysecure.keychain.KeychainTestRunner;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo.TokenType; import org.sufficientlysecure.keychain.securitytoken.CommandApdu;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo.TransportType; import org.sufficientlysecure.keychain.securitytoken.KeyType;
import org.sufficientlysecure.keychain.securitytoken.OpenPgpCapabilities;
import org.sufficientlysecure.keychain.securitytoken.OpenPgpCommandApduFactory;
import org.sufficientlysecure.keychain.securitytoken.ResponseApdu;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -33,8 +27,8 @@ import static org.mockito.Mockito.when;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
@RunWith(KeychainTestRunner.class) @RunWith(KeychainTestRunner.class)
public class SecurityTokenChangeKeyUseCaseTest { public class SecurityTokenChangeKeyTokenOpTest {
SecurityTokenChangeKeyUseCase useCase; SecurityTokenChangeKeyTokenOp useCase;
OpenPgpCommandApduFactory commandFactory; OpenPgpCommandApduFactory commandFactory;
SecurityTokenConnection securityTokenConnection; SecurityTokenConnection securityTokenConnection;
@@ -49,7 +43,7 @@ public class SecurityTokenChangeKeyUseCaseTest {
commandFactory = mock(OpenPgpCommandApduFactory.class); commandFactory = mock(OpenPgpCommandApduFactory.class);
when(securityTokenConnection.getCommandFactory()).thenReturn(commandFactory); when(securityTokenConnection.getCommandFactory()).thenReturn(commandFactory);
useCase = SecurityTokenChangeKeyUseCase.create(securityTokenConnection); useCase = SecurityTokenChangeKeyTokenOp.create(securityTokenConnection);
} }
@@ -128,6 +122,6 @@ public class SecurityTokenChangeKeyUseCaseTest {
} }
UncachedKeyRing readRingFromResource(String name) throws Exception { UncachedKeyRing readRingFromResource(String name) throws Exception {
return UncachedKeyRing.fromStream(SecurityTokenChangeKeyUseCaseTest.class.getResourceAsStream(name)).next(); return UncachedKeyRing.fromStream(SecurityTokenChangeKeyTokenOpTest.class.getResourceAsStream(name)).next();
} }
} }