Skip to content

Commit

Permalink
v2.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dschuermann committed Aug 26, 2019
1 parent e93c645 commit 793a9b3
Show file tree
Hide file tree
Showing 52 changed files with 1,297 additions and 418 deletions.
1 change: 0 additions & 1 deletion hwsecurity-fido/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ android {

defaultConfig {
minSdkVersion 14
versionCode rootProject.ext.hwSdkVersionCode
versionName rootProject.ext.hwSdkVersionName
vectorDrawables.useSupportLibrary = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
import androidx.lifecycle.Lifecycle.Event;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import de.cotech.hw.exceptions.TransportGoneException;

import de.cotech.hw.exceptions.SecurityKeyLostException;
import de.cotech.hw.fido.exceptions.FidoPresenceRequiredException;
import de.cotech.hw.fido.internal.FidoU2fAppletConnection;
import de.cotech.hw.util.HwTimber;
Expand Down Expand Up @@ -84,7 +85,7 @@ public void run() {
} catch (InterruptedException e) {
HwTimber.e("Fido operation was interrupted");
break;
} catch (TransportGoneException e) {
} catch (SecurityKeyLostException e) {
HwTimber.e("Transport gone during fido operation");
break;
} catch (FidoPresenceRequiredException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

package de.cotech.hw.fido.internal.utils;

import android.content.Context;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Build;
Expand All @@ -41,13 +40,13 @@
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class AnimatedVectorDrawableHelper {

public static void startAnimation(Context context, ImageView imageView, int resId) {
startAnimation(context, imageView, resId, null);
public static void startAnimation(ImageView imageView, int resId) {
startAnimation(imageView, resId, null);
}

public static void startAnimation(Context context, ImageView imageView, int resId, Animatable2Compat.AnimationCallback animationCallback) {
public static void startAnimation(ImageView imageView, int resId, Animatable2Compat.AnimationCallback animationCallback) {
if (Build.VERSION.SDK_INT <= 24) {
AnimatedVectorDrawableCompat avdCompat = setAndStartAnimatedVectorDrawableSdk24(context, imageView, resId);
AnimatedVectorDrawableCompat avdCompat = setAndStartAnimatedVectorDrawableSdk24(imageView, resId);
if (animationCallback != null) {
avdCompat.registerAnimationCallback(animationCallback);
}
Expand All @@ -60,7 +59,7 @@ public static void startAnimation(Context context, ImageView imageView, int resI
}
}

public static void startAndLoopAnimation(Context context, ImageView imageView, int resId) {
public static void startAndLoopAnimation(ImageView imageView, int resId) {
Animatable2Compat.AnimationCallback animationCallback = new Animatable2Compat.AnimationCallback() {
@NonNull
private final Handler fHandler = new Handler(Looper.getMainLooper());
Expand All @@ -73,7 +72,7 @@ public void onAnimationEnd(@NonNull Drawable drawable) {

fHandler.post(() -> {
if (Build.VERSION.SDK_INT <= 24) {
AnimatedVectorDrawableCompat avdCompat = setAndStartAnimatedVectorDrawableSdk24(context, imageView, resId);
AnimatedVectorDrawableCompat avdCompat = setAndStartAnimatedVectorDrawableSdk24(imageView, resId);
avdCompat.registerAnimationCallback(this);
} else {
((Animatable) drawable).start();
Expand All @@ -83,7 +82,7 @@ public void onAnimationEnd(@NonNull Drawable drawable) {
};

if (Build.VERSION.SDK_INT <= 24) {
AnimatedVectorDrawableCompat avdCompat = setAndStartAnimatedVectorDrawableSdk24(context, imageView, resId);
AnimatedVectorDrawableCompat avdCompat = setAndStartAnimatedVectorDrawableSdk24(imageView, resId);
avdCompat.registerAnimationCallback(animationCallback);
} else {
imageView.setImageResource(resId);
Expand All @@ -93,8 +92,8 @@ public void onAnimationEnd(@NonNull Drawable drawable) {
}
}

private static AnimatedVectorDrawableCompat setAndStartAnimatedVectorDrawableSdk24(Context context, ImageView imageView, int resId) {
AnimatedVectorDrawableCompat avdCompat = AnimatedVectorDrawableCompat.create(context, resId);
private static AnimatedVectorDrawableCompat setAndStartAnimatedVectorDrawableSdk24(ImageView imageView, int resId) {
AnimatedVectorDrawableCompat avdCompat = AnimatedVectorDrawableCompat.create(imageView.getContext(), resId);

// on SDK <= 24, the alphaFill values are not resetted properly to their initial state
// The states of AnimatedVectorDrawables are stored centrally per resource.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.drawable.Drawable;
import android.nfc.TagLostException;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
Expand All @@ -60,6 +59,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.UiThread;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Guideline;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
Expand All @@ -84,6 +84,7 @@
import de.cotech.hw.SecurityKeyCallback;
import de.cotech.hw.SecurityKeyException;
import de.cotech.hw.SecurityKeyManager;
import de.cotech.hw.exceptions.SecurityKeyLostException;
import de.cotech.hw.fido.FidoAuthenticateCallback;
import de.cotech.hw.fido.FidoAuthenticateRequest;
import de.cotech.hw.fido.FidoAuthenticateResponse;
Expand All @@ -108,6 +109,10 @@ public class FidoDialogFragment extends BottomSheetDialogFragment implements Sec

private static final long TIME_DELAYED_STATE_CHANGE = 3000;

static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

private OnFidoRegisterCallback fidoRegisterCallback;
private OnFidoAuthenticateCallback fidoAuthenticateCallback;

Expand Down Expand Up @@ -639,7 +644,7 @@ public void onAnimationEnd(Drawable drawable) {
}
};

AnimatedVectorDrawableHelper.startAnimation(getActivity(), imageNfcFullscreen, R.drawable.hwsecurity_nfc_handling, animationCallback);
AnimatedVectorDrawableHelper.startAnimation(imageNfcFullscreen, R.drawable.hwsecurity_nfc_handling, animationCallback);
}

private void fadeToNfcSweetSpot() {
Expand Down Expand Up @@ -715,7 +720,7 @@ private void showNfcSweetSpot() {
textError.setVisibility(View.GONE);
});

AnimatedVectorDrawableHelper.startAndLoopAnimation(getActivity(), sweetspotIndicator, R.drawable.hwsecurity_nfc_sweet_spot_a);
AnimatedVectorDrawableHelper.startAndLoopAnimation(sweetspotIndicator, R.drawable.hwsecurity_nfc_sweet_spot_a);
}

private void animateSelectUsb() {
Expand All @@ -728,7 +733,7 @@ public void onTransitionStart(@NonNull Transition transition) {

@Override
public void onTransitionEnd(@NonNull Transition transition) {
AnimatedVectorDrawableHelper.startAndLoopAnimation(getActivity(), imageUsb, R.drawable.hwsecurity_usb_handling_a);
AnimatedVectorDrawableHelper.startAndLoopAnimation(imageUsb, R.drawable.hwsecurity_usb_handling_a);
}

@Override
Expand Down Expand Up @@ -766,7 +771,7 @@ public void onTransitionStart(@NonNull Transition transition) {

@Override
public void onTransitionEnd(@NonNull Transition transition) {
AnimatedVectorDrawableHelper.startAndLoopAnimation(getActivity(), imageUsb, R.drawable.hwsecurity_usb_handling_b);
AnimatedVectorDrawableHelper.startAndLoopAnimation(imageUsb, R.drawable.hwsecurity_usb_handling_b);
}

@Override
Expand Down Expand Up @@ -797,7 +802,7 @@ public void onTransitionResume(@NonNull Transition transition) {
private void animateUsbPressButton() {
TransitionManager.beginDelayedTransition(innerBottomSheet);
textTitle.setText(R.string.hwsecurity_title_usb_button);
AnimatedVectorDrawableHelper.startAndLoopAnimation(getActivity(), imageUsb, R.drawable.hwsecurity_usb_handling_b);
AnimatedVectorDrawableHelper.startAndLoopAnimation(imageUsb, R.drawable.hwsecurity_usb_handling_b);
}

private void animateError() {
Expand All @@ -815,7 +820,7 @@ private void animateError() {
textError.setVisibility(View.VISIBLE);
imageError.setVisibility(View.VISIBLE);

AnimatedVectorDrawableHelper.startAnimation(getActivity(), imageError, R.drawable.hwsecurity_error);
AnimatedVectorDrawableHelper.startAnimation(imageError, R.drawable.hwsecurity_error);
}

@UiThread
Expand Down Expand Up @@ -913,7 +918,7 @@ private void handleError(IOException exception) {
showError(getString(R.string.hwsecurity_error_wrong_key_handle));
} catch (SecurityKeyException e) {
showError(getString(R.string.hwsecurity_error_internal, e.getShortErrorName()));
} catch (TagLostException e) {
} catch (SecurityKeyLostException e) {
// not handled
} catch (IOException e) {
showError(getString(R.string.hwsecurity_error_internal, e.getMessage()));
Expand All @@ -933,7 +938,8 @@ private void showError(String text) {

private int resolveColorFromAttr(@AttrRes int resId) {
TypedValue outValue = new TypedValue();
bottomSheet.getContext().getTheme().resolveAttribute(resId, outValue, true);
// must be the themed context to work correctly on Android < 5
innerBottomSheet.getContext().getTheme().resolveAttribute(resId, outValue, true);
return outValue.data;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public abstract static class Builder {
* This sets the content of the window as 'secure', preventing it from appearing in screenshots,
* screen recordings or from being viewed on non-secure displays.
* <p>
* Default: false (because FIDO U2F requires no PIN input)
* Default: false (because FIDO U2F does not require PIN input)
*/
public abstract Builder setPreventScreenshots(boolean preventScreenshots);

Expand Down
2 changes: 1 addition & 1 deletion hwsecurity-openpgp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,4 @@ dokka {
prefix = "de.cotech.hw.openpgp.internal"
suppress = true
}
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@


public class OpenPgpSecurityKey extends SecurityKey {
private static final ByteSecret DEFAULT_ADMIN_PIN = ByteSecret.unsafeFromString("12345678");
private static final ByteSecret DEFAULT_PUK = ByteSecret.unsafeFromString("12345678");

public final OpenPgpAppletConnection openPgpAppletConnection;

Expand Down Expand Up @@ -104,27 +104,29 @@ public PublicKey retrievePublicKey(KeyType keyType) throws IOException {
*/
@AnyThread
public boolean isSecurityKeyEmpty() {
return !openPgpAppletConnection.getOpenPgpCapabilities().hasEncryptKey();
return !openPgpAppletConnection.getOpenPgpCapabilities().hasSignKey()
&& !openPgpAppletConnection.getOpenPgpCapabilities().hasEncryptKey()
&& !openPgpAppletConnection.getOpenPgpCapabilities().hasAuthKey();
}

/**
* This method directly performs IO with the security token, and should therefore not be called on the UI thread.
*/
@WorkerThread
@RestrictTo(Scope.LIBRARY_GROUP)
public void updatePinPukUsingDefaultPuk(ByteSecret newPin, ByteSecret newPuk) throws IOException {
public void updatePinAndPukUsingDefaultPuk(ByteSecret newPin, ByteSecret newPuk) throws IOException {
ModifyPinOp modifyPinOp = ModifyPinOp.create(openPgpAppletConnection);
modifyPinOp.modifyPw1andPw3Pins(DEFAULT_ADMIN_PIN, newPin, newPuk);
modifyPinOp.modifyPw1AndPw3(DEFAULT_PUK, newPin, newPuk);
}

/**
* This method directly performs IO with the security token, and should therefore not be called on the UI thread.
*/
@WorkerThread
@RestrictTo(Scope.LIBRARY_GROUP)
public void updatePinUsingPuk(ByteSecret puk, ByteSecret newPin) throws IOException {
public void updatePinUsingPuk(ByteSecret currentPuk, ByteSecret newPin) throws IOException {
ModifyPinOp modifyPinOp = ModifyPinOp.create(openPgpAppletConnection);
modifyPinOp.modifyPw1Pin(puk, newPin);
modifyPinOp.modifyPw1Pin(currentPuk, newPin);
}

/**
Expand All @@ -142,19 +144,17 @@ public void updatePinUsingPuk(ByteSecret puk, ByteSecret newPin) throws IOExcept
public void wipeAndVerify() throws IOException {
ResetAndWipeOp resetAndWipe = ResetAndWipeOp.create(openPgpAppletConnection);
resetAndWipe.resetAndWipeSecurityKey();
openPgpAppletConnection.verifyAdminPin(DEFAULT_ADMIN_PIN);
openPgpAppletConnection.verifyPuk(DEFAULT_PUK);
}

@WorkerThread
private boolean verifyAdminPinIfPossible() throws IOException {
boolean encryptFpIsEmpty = !openPgpAppletConnection.getOpenPgpCapabilities().hasEncryptKey();
if (encryptFpIsEmpty) {
private boolean isInFactoryDefaultState() throws IOException {
if (isSecurityKeyEmpty()) {
try {
// make one attempt at entering the default admin pin. if that fails, wipe the card
openPgpAppletConnection.verifyAdminPin(DEFAULT_ADMIN_PIN);
// make one attempt at entering the default PUK
openPgpAppletConnection.verifyPuk(DEFAULT_PUK);
return true;
} catch (SecurityKeyException e) {
// ignore, and wipe security key instead
return false;
}
} else {
Expand All @@ -180,7 +180,8 @@ private boolean verifyAdminPinIfPossible() throws IOException {
@WorkerThread
public PairedSecurityKey setupPairedKey(PinProvider pinProvider) throws IOException {
ByteSecret pairedPin = pinProvider.getPin(getOpenPgpInstanceAid());
return setupPairedKey(pairedPin, pairedPin);
ByteSecret pairedPuk = pinProvider.getPuk(getOpenPgpInstanceAid());
return setupPairedKey(pairedPin, pairedPuk);
}

@WorkerThread
Expand All @@ -190,8 +191,8 @@ public PairedSecurityKey setupPairedKey(ByteSecret newPin, ByteSecret newPuk) th

@WorkerThread
public PairedSecurityKey setupPairedKey(ByteSecret newPin, ByteSecret newPuk, boolean encryptionOnly) throws IOException {
boolean verifySuccessful = verifyAdminPinIfPossible();
if (!verifySuccessful) {
boolean isInFactoryDefaultState = isInFactoryDefaultState();
if (!isInFactoryDefaultState) {
wipeAndVerify();
}

Expand All @@ -213,7 +214,7 @@ public PairedSecurityKey setupPairedKey(ByteSecret newPin, ByteSecret newPuk, bo
KeyPair encryptionKeyPair = rsaEncryptUtil.generateRsa2048KeyPair();
byte[] encryptFingerprint = changeKeyRsaOp.changeKey(KeyType.ENCRYPT, encryptionKeyPair, timestamp);

updatePinPukUsingDefaultPuk(newPin, newPuk);
updatePinAndPukUsingDefaultPuk(newPin, newPuk);

openPgpAppletConnection.refreshConnectionCapabilities();

Expand All @@ -229,7 +230,7 @@ public PairedSecurityKey setupPairedKey(ByteSecret newPin, ByteSecret newPuk, bo
byte[] encryptFingerprint = changeKeyRsaOp.changeKey(KeyType.ENCRYPT, encryptionKeyPair, timestamp);
byte[] signFingerprint = changeKeyRsaOp.changeKey(KeyType.SIGN, signKeyPair, timestamp);
byte[] authFingerprint = changeKeyRsaOp.changeKey(KeyType.AUTH, authKeyPair, timestamp);
updatePinPukUsingDefaultPuk(newPin, newPuk);
updatePinAndPukUsingDefaultPuk(newPin, newPuk);

openPgpAppletConnection.refreshConnectionCapabilities();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import de.cotech.hw.exceptions.AuthenticationMethodBlockedException;
import de.cotech.hw.exceptions.SecurityStatusNotSatisfiedException;

public class OpenPgpCardBlockedException extends AuthenticationMethodBlockedException {
public static final int SW_CARD_BLOCKED = SW_AUTHENTICATION_METHOD_BLOCKED;
public class OpenPgpLockedException extends AuthenticationMethodBlockedException {
public static final int SW_OPENPGP_LOCKED = SW_AUTHENTICATION_METHOD_BLOCKED;

// older YubiKey NEO returns 63C0 (0 retries), reproduce with YubiKey NEO, SN 2624165
public static final int SW_OPENPGP_LOCKED_YKNEO = 0x63C0;

@RestrictTo(Scope.LIBRARY_GROUP)
public OpenPgpCardBlockedException() {
super("Security Key returned error, card blocked / the PIN/PUK has been entered 3 times wrong.");
public OpenPgpLockedException() {
super("Security Key returned error: PIN/PUK locked, an incorrect PIN/PUK has been entered 3 times.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,23 @@
import de.cotech.hw.exceptions.WrongRequestLengthException;

public class OpenPgpPinTooShortException extends SecurityKeyException {
/*
* Used in
* - ykneo-openpgp >= 1.0.11
* https://github.com/Yubico/ykneo-openpgp/commit/b49ce8241917e7c087a4dab7b2c755420ff4500f
* - YubiKey 5C
*/
public static final int SW_WRONG_DATA = WrongDataException.SW_WRONG_DATA;
/*
* Used in
* - ykneo-openpgp >= 1.0.11
* https://github.com/Yubico/ykneo-openpgp/commit/b49ce8241917e7c087a4dab7b2c755420ff4500f
* - YubiKey 5C
*/
public static final int SW_WRONG_DATA = WrongDataException.SW_WRONG_DATA;

/*
* Used in
* - ykneo-openpgp < 1.0.10
* - SmartPGP
*/
public static final int SW_WRONG_REQUEST_LENGTH = WrongRequestLengthException.SW_WRONG_REQUEST_LENGTH;
/*
* Used in
* - ykneo-openpgp < 1.0.10
* - SmartPGP
*/
public static final int SW_WRONG_REQUEST_LENGTH = WrongRequestLengthException.SW_WRONG_REQUEST_LENGTH;

public OpenPgpPinTooShortException() {
super("OpenPgpPinTooShortException", 0);
}
public OpenPgpPinTooShortException() {
super("Security Key returned error: PIN too short.", 0);
}

public OpenPgpPinTooShortException(String longErrorMessage) {
super(longErrorMessage, "OpenPgpPinTooShortException", 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

package de.cotech.hw.openpgp.exceptions;


import java.io.IOException;

public class OpenPgpPublicKeyUnavailableException extends IOException {
Expand Down
Loading

0 comments on commit 793a9b3

Please sign in to comment.