diff --git a/android/src/main/java/com/yubico/yubikit/android/transport/usb/UsbDeviceManager.java b/android/src/main/java/com/yubico/yubikit/android/transport/usb/UsbDeviceManager.java index 145d0ed6..4965ee81 100755 --- a/android/src/main/java/com/yubico/yubikit/android/transport/usb/UsbDeviceManager.java +++ b/android/src/main/java/com/yubico/yubikit/android/transport/usb/UsbDeviceManager.java @@ -22,7 +22,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.hardware.usb.UsbConfiguration; +import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.os.Build; @@ -48,6 +51,35 @@ final class UsbDeviceManager { private static final org.slf4j.Logger logger = LoggerFactory.getLogger(UsbDeviceManager.class); + public static boolean isSupportedYubicoDevice(@Nullable UsbDevice device) { + return device != null && device.getVendorId() == YUBICO_VENDOR_ID; + } + + public static boolean isSupportedDevice(@Nullable UsbDevice device) { + return isSupportedYubicoDevice(device) || isFidoUsbDevice(device); + } + + private static boolean isFidoUsbDevice(@Nullable UsbDevice device) { + if (device == null) { + return false; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + for (int configIndex = 0; configIndex < device.getConfigurationCount(); configIndex++) { + UsbConfiguration configuration = device.getConfiguration(configIndex); + for (int i = 0; i < configuration.getInterfaceCount(); i++) { + UsbInterface usbInterface = configuration.getInterface(i); + if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID && + usbInterface.getInterfaceSubclass() == 0) { + return true; + } + } + } + } + + return false; + } + private static synchronized UsbDeviceManager getInstance() { if (instance == null) { instance = new UsbDeviceManager(); @@ -81,7 +113,7 @@ private synchronized void addUsbListener(Context context, UsbDeviceListener list intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); context.registerReceiver(broadcastReceiver, intentFilter); for (UsbDevice usbDevice : usbDevices) { - if (usbDevice.getVendorId() == YUBICO_VENDOR_ID) { + if (isSupportedDevice(usbDevice)) { onDeviceAttach(usbDevice); } } @@ -181,7 +213,7 @@ private class DeviceBroadcastReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); UsbDevice usbDevice = getUsbManagerExtraDevice(intent); - if (usbDevice == null || usbDevice.getVendorId() != YUBICO_VENDOR_ID) { + if (!isSupportedDevice(usbDevice)) { return; } diff --git a/android/src/main/java/com/yubico/yubikit/android/transport/usb/UsbYubiKeyDevice.java b/android/src/main/java/com/yubico/yubikit/android/transport/usb/UsbYubiKeyDevice.java index 7ec07427..cdc7390c 100755 --- a/android/src/main/java/com/yubico/yubikit/android/transport/usb/UsbYubiKeyDevice.java +++ b/android/src/main/java/com/yubico/yubikit/android/transport/usb/UsbYubiKeyDevice.java @@ -16,7 +16,8 @@ package com.yubico.yubikit.android.transport.usb; -import static com.yubico.yubikit.android.transport.usb.UsbDeviceManager.YUBICO_VENDOR_ID; +import static com.yubico.yubikit.android.transport.usb.UsbDeviceManager.isSupportedDevice; +import static com.yubico.yubikit.android.transport.usb.UsbDeviceManager.isSupportedYubicoDevice; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; @@ -68,11 +69,13 @@ public class UsbYubiKeyDevice implements YubiKeyDevice, Closeable { public UsbYubiKeyDevice(UsbManager usbManager, UsbDevice usbDevice) throws IllegalArgumentException { - if (usbDevice.getVendorId() != YUBICO_VENDOR_ID) { - throw new IllegalArgumentException("Invalid vendor id"); + if (!isSupportedDevice(usbDevice)) { + throw new IllegalArgumentException("Device not supported"); } - this.usbPid = UsbPid.fromValue(usbDevice.getProductId()); + this.usbPid = isSupportedYubicoDevice(usbDevice) + ? UsbPid.fromValue(usbDevice.getProductId()) + : UsbPid.FIDO_SECURITY_KEY; this.connectionManager = new ConnectionManager(usbManager, usbDevice); this.usbDevice = usbDevice; diff --git a/core/src/main/java/com/yubico/yubikit/core/UsbPid.java b/core/src/main/java/com/yubico/yubikit/core/UsbPid.java index 93a5f89d..2812a634 100644 --- a/core/src/main/java/com/yubico/yubikit/core/UsbPid.java +++ b/core/src/main/java/com/yubico/yubikit/core/UsbPid.java @@ -33,7 +33,8 @@ public enum UsbPid { YK4_OTP_CCID(0x0405, YubiKeyType.YK4, UsbInterface.OTP | UsbInterface.CCID), YK4_FIDO_CCID(0x0406, YubiKeyType.YK4, UsbInterface.FIDO | UsbInterface.CCID), YK4_OTP_FIDO_CCID(0x0407, YubiKeyType.YK4, UsbInterface.OTP | UsbInterface.FIDO | UsbInterface.CCID), - YKP_OTP_FIDO(0x0410, YubiKeyType.YKP, UsbInterface.OTP | UsbInterface.FIDO); + YKP_OTP_FIDO(0x0410, YubiKeyType.YKP, UsbInterface.OTP | UsbInterface.FIDO), + FIDO_SECURITY_KEY(-1, YubiKeyType.FIDO_SECURITY_KEY, UsbInterface.FIDO); public final int value; public final YubiKeyType type; diff --git a/core/src/main/java/com/yubico/yubikit/core/YubiKeyType.java b/core/src/main/java/com/yubico/yubikit/core/YubiKeyType.java index 8e696166..3fd040e0 100644 --- a/core/src/main/java/com/yubico/yubikit/core/YubiKeyType.java +++ b/core/src/main/java/com/yubico/yubikit/core/YubiKeyType.java @@ -21,7 +21,8 @@ public enum YubiKeyType { NEO("YubiKey NEO"), SKY("Security Key by Yubico"), YKP("YubiKey Plus"), - YK4("YubiKey"); + YK4("YubiKey"), + FIDO_SECURITY_KEY("Fido Security Key"); public final String name; diff --git a/testing-android/src/main/java/com/yubico/yubikit/testing/framework/YKInstrumentedTests.java b/testing-android/src/main/java/com/yubico/yubikit/testing/framework/YKInstrumentedTests.java index 8d6b2023..7dbb5db7 100755 --- a/testing-android/src/main/java/com/yubico/yubikit/testing/framework/YKInstrumentedTests.java +++ b/testing-android/src/main/java/com/yubico/yubikit/testing/framework/YKInstrumentedTests.java @@ -58,6 +58,11 @@ public void getYubiKey() throws InterruptedException { ? ((UsbYubiKeyDevice) device).getPid() : null; + + if (usbPid == UsbPid.FIDO_SECURITY_KEY) { + return; + } + try (SmartCardConnection connection = device.openConnection(SmartCardConnection.class)) { final DeviceInfo deviceInfo = DeviceUtil.readInfo(connection, usbPid); if (deviceInfo.getVersion().major == 0) {