SecurityTokenConnection code style

This commit is contained in:
Vincent Breitmoser
2018-01-12 15:44:23 +01:00
parent 7212148913
commit bb2b37cff6
4 changed files with 71 additions and 69 deletions

View File

@@ -48,26 +48,27 @@ public class SecurityTokenConnection {
private static SecurityTokenConnection sCachedInstance; private static SecurityTokenConnection sCachedInstance;
@NonNull @NonNull
private final Transport mTransport; private final Transport transport;
@Nullable @Nullable
private final Passphrase mPin; private final Passphrase cachedPin;
private final OpenPgpCommandApduFactory commandFactory; private final OpenPgpCommandApduFactory commandFactory;
private TokenType tokenType; private TokenType tokenType;
private CardCapabilities mCardCapabilities; private CardCapabilities cardCapabilities;
private OpenPgpCapabilities mOpenPgpCapabilities; private OpenPgpCapabilities openPgpCapabilities;
private SecureMessaging mSecureMessaging;
private boolean mPw1ValidatedForSignature; private SecureMessaging secureMessaging;
private boolean mPw1ValidatedForDecrypt; // Mode 82 does other things; consider renaming?
private boolean mPw3Validated; private boolean isPw1ValidatedForSignature; // Mode 81
private boolean isPw1ValidatedForOther; // Mode 82
private boolean isPw3Validated;
public static SecurityTokenConnection getInstanceForTransport( public static SecurityTokenConnection getInstanceForTransport(
@NonNull Transport transport, @Nullable Passphrase pin) { @NonNull Transport transport, @Nullable Passphrase pin) {
if (sCachedInstance == null || !sCachedInstance.isPersistentConnectionAllowed() || if (sCachedInstance == null || !sCachedInstance.isPersistentConnectionAllowed() ||
!sCachedInstance.isConnected() || !sCachedInstance.mTransport.equals(transport) || !sCachedInstance.isConnected() || !sCachedInstance.transport.equals(transport) ||
(pin != null && !pin.equals(sCachedInstance.mPin))) { (pin != null && !pin.equals(sCachedInstance.cachedPin))) {
sCachedInstance = new SecurityTokenConnection(transport, pin, new OpenPgpCommandApduFactory()); sCachedInstance = new SecurityTokenConnection(transport, pin, new OpenPgpCommandApduFactory());
} }
return sCachedInstance; return sCachedInstance;
@@ -81,14 +82,14 @@ public class SecurityTokenConnection {
@VisibleForTesting @VisibleForTesting
SecurityTokenConnection(@NonNull Transport transport, @Nullable Passphrase pin, SecurityTokenConnection(@NonNull Transport transport, @Nullable Passphrase pin,
OpenPgpCommandApduFactory commandFactory) { OpenPgpCommandApduFactory commandFactory) {
this.mTransport = transport; this.transport = transport;
this.mPin = pin; this.cachedPin = pin;
this.commandFactory = commandFactory; this.commandFactory = commandFactory;
} }
OpenPgpCapabilities getOpenPgpCapabilities() { OpenPgpCapabilities getOpenPgpCapabilities() {
return mOpenPgpCapabilities; return openPgpCapabilities;
} }
OpenPgpCommandApduFactory getCommandFactory() { OpenPgpCommandApduFactory getCommandFactory() {
@@ -96,8 +97,8 @@ public class SecurityTokenConnection {
} }
void maybeInvalidatePw1() { void maybeInvalidatePw1() {
if (!mOpenPgpCapabilities.isPw1ValidForMultipleSignatures()) { if (!openPgpCapabilities.isPw1ValidForMultipleSignatures()) {
mPw1ValidatedForSignature = false; isPw1ValidatedForSignature = false;
} }
} }
@@ -128,10 +129,10 @@ public class SecurityTokenConnection {
@VisibleForTesting @VisibleForTesting
void connectToDevice(Context context) throws IOException { void connectToDevice(Context context) throws IOException {
// Connect on transport layer // Connect on transport layer
mTransport.connect(); transport.connect();
// dummy instance for initial communicate() calls // dummy instance for initial communicate() calls
mCardCapabilities = new CardCapabilities(); cardCapabilities = new CardCapabilities();
determineTokenType(); determineTokenType();
@@ -144,15 +145,15 @@ public class SecurityTokenConnection {
refreshConnectionCapabilities(); refreshConnectionCapabilities();
mPw1ValidatedForSignature = false; isPw1ValidatedForSignature = false;
mPw1ValidatedForDecrypt = false; isPw1ValidatedForOther = false;
mPw3Validated = false; isPw3Validated = false;
if (mOpenPgpCapabilities.isHasSCP11bSM()) { if (openPgpCapabilities.isHasSCP11bSM()) {
try { try {
SCP11bSecureMessaging.establish(this, context, commandFactory); SCP11bSecureMessaging.establish(this, context, commandFactory);
} catch (SecureMessagingException e) { } catch (SecureMessagingException e) {
mSecureMessaging = null; secureMessaging = null;
Log.e(Constants.TAG, "failed to establish secure messaging", e); Log.e(Constants.TAG, "failed to establish secure messaging", e);
} }
} }
@@ -160,7 +161,7 @@ public class SecurityTokenConnection {
@VisibleForTesting @VisibleForTesting
void determineTokenType() throws IOException { void determineTokenType() throws IOException {
tokenType = mTransport.getTokenTypeIfAvailable(); tokenType = transport.getTokenTypeIfAvailable();
if (tokenType != null) { if (tokenType != null) {
return; return;
} }
@@ -192,12 +193,12 @@ public class SecurityTokenConnection {
@VisibleForTesting @VisibleForTesting
void setConnectionCapabilities(OpenPgpCapabilities openPgpCapabilities) throws IOException { void setConnectionCapabilities(OpenPgpCapabilities openPgpCapabilities) throws IOException {
this.mOpenPgpCapabilities = openPgpCapabilities; this.openPgpCapabilities = openPgpCapabilities;
this.mCardCapabilities = new CardCapabilities(openPgpCapabilities.getHistoricalBytes()); this.cardCapabilities = new CardCapabilities(openPgpCapabilities.getHistoricalBytes());
} }
public void resetPin(byte[] newPin, Passphrase adminPin) throws IOException { public void resetPin(byte[] newPin, Passphrase adminPin) throws IOException {
if (!mPw3Validated) { if (!isPw3Validated) {
verifyAdminPin(adminPin); verifyAdminPin(adminPin);
} }
@@ -236,7 +237,7 @@ public class SecurityTokenConnection {
CommandApdu changePin = commandFactory.createChangePw3Command(pin, newAdminPin); CommandApdu changePin = commandFactory.createChangePw3Command(pin, newAdminPin);
ResponseApdu response = communicate(changePin); ResponseApdu response = communicate(changePin);
mPw3Validated = false; isPw3Validated = false;
if (!response.isSuccess()) { if (!response.isSuccess()) {
throw new CardException("Failed to change PIN", response.getSw()); throw new CardException("Failed to change PIN", response.getSw());
@@ -247,35 +248,35 @@ public class SecurityTokenConnection {
* Verifies the user's PW1 with the appropriate mode. * Verifies the user's PW1 with the appropriate mode.
*/ */
void verifyPinForSignature() throws IOException { void verifyPinForSignature() throws IOException {
if (mPw1ValidatedForSignature) { if (isPw1ValidatedForSignature) {
return; return;
} }
if (mPin == null) { if (cachedPin == null) {
throw new IllegalStateException("Connection not initialized with Pin!"); throw new IllegalStateException("Connection not initialized with Pin!");
} }
byte[] pin = mPin.toStringUnsafe().getBytes(); byte[] pin = cachedPin.toStringUnsafe().getBytes();
ResponseApdu response = communicate(commandFactory.createVerifyPw1ForSignatureCommand(pin)); ResponseApdu response = communicate(commandFactory.createVerifyPw1ForSignatureCommand(pin));
if (!response.isSuccess()) { if (!response.isSuccess()) {
throw new CardException("Bad PIN!", response.getSw()); throw new CardException("Bad PIN!", response.getSw());
} }
mPw1ValidatedForSignature = true; isPw1ValidatedForSignature = true;
} }
/** /**
* Verifies the user's PW1 with the appropriate mode. * Verifies the user's PW1 with the appropriate mode.
*/ */
void verifyPinForOther() throws IOException { void verifyPinForOther() throws IOException {
if (mPw1ValidatedForDecrypt) { if (isPw1ValidatedForOther) {
return; return;
} }
if (mPin == null) { if (cachedPin == null) {
throw new IllegalStateException("Connection not initialized with Pin!"); throw new IllegalStateException("Connection not initialized with Pin!");
} }
byte[] pin = mPin.toStringUnsafe().getBytes(); byte[] pin = cachedPin.toStringUnsafe().getBytes();
// Command APDU for VERIFY command (page 32) // Command APDU for VERIFY command (page 32)
ResponseApdu response = communicate(commandFactory.createVerifyPw1ForOtherCommand(pin)); ResponseApdu response = communicate(commandFactory.createVerifyPw1ForOtherCommand(pin));
@@ -283,14 +284,14 @@ public class SecurityTokenConnection {
throw new CardException("Bad PIN!", response.getSw()); throw new CardException("Bad PIN!", response.getSw());
} }
mPw1ValidatedForDecrypt = true; isPw1ValidatedForOther = true;
} }
/** /**
* Verifies the user's PW1 or PW3 with the appropriate mode. * Verifies the user's PW1 or PW3 with the appropriate mode.
*/ */
void verifyAdminPin(Passphrase adminPin) throws IOException { void verifyAdminPin(Passphrase adminPin) throws IOException {
if (mPw3Validated) { if (isPw3Validated) {
return; return;
} }
// Command APDU for VERIFY command (page 32) // Command APDU for VERIFY command (page 32)
@@ -300,7 +301,7 @@ public class SecurityTokenConnection {
throw new CardException("Bad PIN!", response.getSw()); throw new CardException("Bad PIN!", response.getSw());
} }
mPw3Validated = true; isPw3Validated = true;
} }
/** /**
@@ -310,7 +311,7 @@ public class SecurityTokenConnection {
* @return The fingerprints of all subkeys in a contiguous byte array. * @return The fingerprints of all subkeys in a contiguous byte array.
*/ */
public byte[] getFingerprints() throws IOException { public byte[] getFingerprints() throws IOException {
return mOpenPgpCapabilities.getFingerprints(); return openPgpCapabilities.getFingerprints();
} }
/** /**
@@ -319,11 +320,11 @@ public class SecurityTokenConnection {
* @return Seven bytes in fixed format, plus 0x9000 status word at the end. * @return Seven bytes in fixed format, plus 0x9000 status word at the end.
*/ */
private byte[] getPwStatusBytes() throws IOException { private byte[] getPwStatusBytes() throws IOException {
return mOpenPgpCapabilities.getPwStatusBytes(); return openPgpCapabilities.getPwStatusBytes();
} }
public byte[] getAid() throws IOException { public byte[] getAid() throws IOException {
return mOpenPgpCapabilities.getAid(); return openPgpCapabilities.getAid();
} }
public String getUrl() throws IOException { public String getUrl() throws IOException {
@@ -353,9 +354,9 @@ public class SecurityTokenConnection {
* @throws IOException * @throws IOException
*/ */
ResponseApdu communicate(CommandApdu apdu) throws IOException { ResponseApdu communicate(CommandApdu apdu) throws IOException {
if ((mSecureMessaging != null) && mSecureMessaging.isEstablished()) { if ((secureMessaging != null) && secureMessaging.isEstablished()) {
try { try {
apdu = mSecureMessaging.encryptAndSign(apdu); apdu = secureMessaging.encryptAndSign(apdu);
} catch (SecureMessagingException e) { } catch (SecureMessagingException e) {
clearSecureMessaging(); clearSecureMessaging();
throw new IOException("secure messaging encrypt/sign failure : " + e.getMessage()); throw new IOException("secure messaging encrypt/sign failure : " + e.getMessage());
@@ -364,16 +365,16 @@ public class SecurityTokenConnection {
ResponseApdu lastResponse = null; ResponseApdu lastResponse = null;
// Transmit // Transmit
if (mCardCapabilities.hasExtended()) { if (cardCapabilities.hasExtended()) {
lastResponse = mTransport.transceive(apdu); lastResponse = transport.transceive(apdu);
} else if (commandFactory.isSuitableForShortApdu(apdu)) { } else if (commandFactory.isSuitableForShortApdu(apdu)) {
CommandApdu shortApdu = commandFactory.createShortApdu(apdu); CommandApdu shortApdu = commandFactory.createShortApdu(apdu);
lastResponse = mTransport.transceive(shortApdu); lastResponse = transport.transceive(shortApdu);
} else if (mCardCapabilities.hasChaining()) { } else if (cardCapabilities.hasChaining()) {
List<CommandApdu> chainedApdus = commandFactory.createChainedApdus(apdu); List<CommandApdu> chainedApdus = commandFactory.createChainedApdus(apdu);
for (int i = 0, totalCommands = chainedApdus.size(); i < totalCommands; i++) { for (int i = 0, totalCommands = chainedApdus.size(); i < totalCommands; i++) {
CommandApdu chainedApdu = chainedApdus.get(i); CommandApdu chainedApdu = chainedApdus.get(i);
lastResponse = mTransport.transceive(chainedApdu); lastResponse = transport.transceive(chainedApdu);
boolean isLastCommand = (i == totalCommands - 1); boolean isLastCommand = (i == totalCommands - 1);
if (!isLastCommand && !lastResponse.isSuccess()) { if (!isLastCommand && !lastResponse.isSuccess()) {
@@ -393,7 +394,7 @@ public class SecurityTokenConnection {
while (lastResponse.getSw1() == APDU_SW1_RESPONSE_AVAILABLE) { while (lastResponse.getSw1() == APDU_SW1_RESPONSE_AVAILABLE) {
// GET RESPONSE ISO/IEC 7816-4 par.7.6.1 // GET RESPONSE ISO/IEC 7816-4 par.7.6.1
CommandApdu getResponse = commandFactory.createGetResponseCommand(lastResponse.getSw2()); CommandApdu getResponse = commandFactory.createGetResponseCommand(lastResponse.getSw2());
lastResponse = mTransport.transceive(getResponse); lastResponse = transport.transceive(getResponse);
result.write(lastResponse.getData()); result.write(lastResponse.getData());
} }
@@ -402,9 +403,9 @@ public class SecurityTokenConnection {
lastResponse = ResponseApdu.fromBytes(result.toByteArray()); lastResponse = ResponseApdu.fromBytes(result.toByteArray());
if ((mSecureMessaging != null) && mSecureMessaging.isEstablished()) { if ((secureMessaging != null) && secureMessaging.isEstablished()) {
try { try {
lastResponse = mSecureMessaging.verifyAndDecrypt(lastResponse); lastResponse = secureMessaging.verifyAndDecrypt(lastResponse);
} catch (SecureMessagingException e) { } catch (SecureMessagingException e) {
clearSecureMessaging(); clearSecureMessaging();
throw new IOException("secure messaging verify/decrypt failure : " + e.getMessage()); throw new IOException("secure messaging verify/decrypt failure : " + e.getMessage());
@@ -433,7 +434,7 @@ public class SecurityTokenConnection {
throw new IOException("Invalid key slot"); throw new IOException("Invalid key slot");
} }
if (!mPw3Validated) { if (!isPw3Validated) {
verifyAdminPin(adminPin); verifyAdminPin(adminPin);
} }
@@ -516,12 +517,12 @@ public class SecurityTokenConnection {
} }
public boolean isPersistentConnectionAllowed() { public boolean isPersistentConnectionAllowed() {
return mTransport.isPersistentConnectionAllowed() && return transport.isPersistentConnectionAllowed() &&
(mSecureMessaging == null || !mSecureMessaging.isEstablished()); (secureMessaging == null || !secureMessaging.isEstablished());
} }
public boolean isConnected() { public boolean isConnected() {
return mTransport.isConnected(); return transport.isConnected();
} }
public TokenType getTokenType() { public TokenType getTokenType() {
@@ -529,15 +530,15 @@ public class SecurityTokenConnection {
} }
public void clearSecureMessaging() { public void clearSecureMessaging() {
if (mSecureMessaging != null) { if (secureMessaging != null) {
mSecureMessaging.clearSession(); secureMessaging.clearSession();
} }
mSecureMessaging = null; secureMessaging = null;
} }
void setSecureMessaging(final SecureMessaging sm) { void setSecureMessaging(SecureMessaging sm) {
clearSecureMessaging(); clearSecureMessaging();
mSecureMessaging = sm; secureMessaging = sm;
} }
public SecurityTokenInfo getTokenInfo() throws IOException { public SecurityTokenInfo getTokenInfo() throws IOException {
@@ -554,18 +555,12 @@ public class SecurityTokenConnection {
String userId = getUserId(); String userId = getUserId();
String url = getUrl(); String url = getUrl();
byte[] pwInfo = getPwStatusBytes(); byte[] pwInfo = getPwStatusBytes();
boolean hasLifeCycleManagement = mCardCapabilities.hasLifeCycleManagement(); boolean hasLifeCycleManagement = cardCapabilities.hasLifeCycleManagement();
TransportType transportType = mTransport.getTransportType(); TransportType transportType = transport.getTransportType();
return SecurityTokenInfo return SecurityTokenInfo
.create(transportType, tokenType, fingerprints, aid, userId, url, pwInfo[4], pwInfo[6], .create(transportType, tokenType, fingerprints, aid, userId, url, pwInfo[4], pwInfo[6],
hasLifeCycleManagement); hasLifeCycleManagement);
} }
public static double parseOpenPgpVersion(final byte[] aid) {
float minv = aid[7];
while (minv > 0) minv /= 10.0;
return aid[6] + minv;
}
} }

View File

@@ -166,6 +166,13 @@ public abstract class SecurityTokenInfo implements Parcelable {
return Version.create(matcher.group(1)); return Version.create(matcher.group(1));
} }
public double getOpenPgpVersion() {
byte[] aid = getAid();
float minv = aid[7];
while (minv > 0) minv /= 10.0;
return aid[6] + minv;
}
@AutoValue @AutoValue
public static abstract class Version implements Comparable<Version> { public static abstract class Version implements Comparable<Version> {

View File

@@ -100,7 +100,7 @@ public class CreateSecurityTokenAlgorithmFragment extends Fragment {
choices.add(new Choice<>(SupportedKeyType.RSA_4096, getResources().getString( choices.add(new Choice<>(SupportedKeyType.RSA_4096, getResources().getString(
R.string.rsa_4096), getResources().getString(R.string.rsa_4096_description_html))); R.string.rsa_4096), getResources().getString(R.string.rsa_4096_description_html)));
final double version = SecurityTokenConnection.parseOpenPgpVersion(mCreateKeyActivity.tokenInfo.getAid()); final double version = mCreateKeyActivity.tokenInfo.getOpenPgpVersion();
if (version >= 3.0) { if (version >= 3.0) {
choices.add(new Choice<>(SupportedKeyType.ECC_P256, getResources().getString( choices.add(new Choice<>(SupportedKeyType.ECC_P256, getResources().getString(

View File

@@ -205,7 +205,7 @@ public class CreateSecurityTokenPinFragment extends Fragment {
mCreateKeyActivity.mSecurityTokenPin = new Passphrase(mPin.getText().toString()); mCreateKeyActivity.mSecurityTokenPin = new Passphrase(mPin.getText().toString());
final double version = SecurityTokenConnection.parseOpenPgpVersion(mCreateKeyActivity.tokenInfo.getAid()); final double version = mCreateKeyActivity.tokenInfo.getOpenPgpVersion();
Fragment frag; Fragment frag;
if (version >= 3.0) { if (version >= 3.0) {