-
Notifications
You must be signed in to change notification settings - Fork 101
Description
Disclaimer
This was debugged with AI and most of the report is generated by AI, but it has been reviewed by a software engineer (me). I can submit a pull request, but Fix 1 has potential of breaking other devices if they have Vendor Specific interface, but expect to be communicated with on interface 0.
Summary
Blockstream Green fails to connect to Ledger Nano S+ devices via USB. The app detects the device but hangs indefinitely during connection. This affects all Nano S+ devices (Product ID 0x5000) running firmware 2.01 or similar versions.
Affected Versions
- Blockstream Green: v5.1.4-dev (and likely earlier versions)
- Device: Ledger Nano S+
- Firmware: 2.01 (and potentially other versions)
- OS: Android 16 (API 36), but likely affects all Android versions
Steps to Reproduce
- Install Bitcoin Legacy app on Ledger Nano S+ (as recommended by Blockstream documentation)
- Open the Bitcoin Legacy app on the Ledger
- Connect Ledger Nano S+ to Android device via USB
- Grant USB permission when prompted
- In Blockstream Green, tap "Connect Hardware Wallet"
- Select "Ledger" from device list
- Select the detected Nano S+ device
- Result: App shows "Logging in..." spinner indefinitely, never completes connection
Expected Behavior
App should successfully connect to the Ledger Nano S+, authenticate the device, and display the wallet interface with balance and transaction history.
Actual Behavior
- Device is detected via USB (VID: 0x2C97, PID: 0x5000)
- USB permission is granted successfully
- App navigates to device connection screen
- Communication stalls after sending initial APDU command
- No error message displayed to user
- App remains in "connecting" state indefinitely
Root Cause Analysis
Two issues were identified in the USB communication layer:
Issue 1: Wrong USB Interface Selection
Location: hardware/src/main/java/com/btchip/comm/android/BTChipTransportAndroid.java
Problem: The code was hardcoded to use Interface 0:
UsbInterface dongleInterface = device.getInterface(0);Impact: Interface 0 is HID (Human Interface Device) class, but Ledger Nano S+ uses Interface 1 (Vendor Specific, Class 255) for application communication.
USB Interface Layout on Nano S+:
- Interface 0: HID Class (0x03) - Keyboard emulation, wrong interface
- Interface 1: Vendor Specific (0xFF) - Correct interface for Ledger apps
- Interface 2: HID Boot Class (0x03) - Boot keyboard, wrong interface
Issue 2: Missing Product ID Support
Location: hardware/src/main/java/com/btchip/comm/android/BTChipTransportAndroid.java
Problem: The Nano S+ product ID (0x5000) was not recognized in the supported devices list.
Current supported product IDs:
- Nano S Legacy: 0x0001
- Nano X Legacy: 0x0004
- Nano S: 0x10xx (upper byte 0x10)
- Nano X: 0x40xx (upper byte 0x40)
- Missing: Nano S+: 0x50xx (upper byte 0x50)
Impact: Device was not recognized as a Ledger device (ledger=false), causing improper initialization of the transport layer.
Technical Details
APDU Communication
The initial APDU command sent was:
CLA: B0 (Ledger vendor-specific)
INS: 01 (Get Version)
P1: 00
P2: 00
Data: None
When using the wrong interface (Interface 0), the Ledger device never responds to this command, causing an indefinite hang.
Log Evidence
Before Fix:
Selected interface 0 (HID)
Creating transport for ledger=false productId=20480
BTChip: => b0010000
[No response - indefinite hang]
After Fix:
Selected Vendor Specific interface 1
Creating transport for ledger=true productId=20480
BTChip: => b0010000
[Device responds correctly]
Proposed Fix
Fix 1: Dynamic USB Interface Selection
Search for the Vendor Specific interface instead of hardcoding interface 0:
// Search for Vendor Specific interface (Class 255)
UsbInterface dongleInterface = null;
for (int i = 0; i < device.getInterfaceCount(); i++) {
UsbInterface iface = device.getInterface(i);
if (iface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC) {
dongleInterface = iface;
break;
}
}
// Fallback to interface 0 if no Vendor Specific interface found
if (dongleInterface == null) {
dongleInterface = device.getInterface(0);
}Fix 2: Add Nano S+ Product ID Support
Add constant and update all device detection logic:
private static final int PID_NANOS_PLUS = 0x50; // Upper byte for 0x50xx range
// Update ledger detection:
ledger = ((device.getProductId() == PID_HID_LEDGER) ||
(device.getProductId() == PID_HID_LEDGER_PROTON) ||
(device.getProductId() == PID_NANOS_LEGACY) ||
(device.getProductId() >> 8 == PID_NANOS) ||
(device.getProductId() == PID_NANOX_LEGACY) ||
(device.getProductId() >> 8 == PID_NANOX) ||
(device.getProductId() >> 8 == PID_NANOS_PLUS)); // Add this line
// Update isLedgerWithScreen():
public static boolean isLedgerWithScreen(final UsbDevice d) {
final int pId = d.getProductId();
final boolean screenDevice = pId == PID_NANOS_LEGACY ||
pId == PID_NANOX_LEGACY ||
pId >> 8 == PID_NANOS ||
pId >> 8 == PID_NANOX ||
pId >> 8 == PID_NANOS_PLUS; // Add this
return screenDevice && d.getVendorId() == VID2;
}
// Update getDevice() enumeration:
if ((device.getVendorId() == VID || device.getVendorId() == VID2) &&
((device.getProductId() == PID_WINUSB) ||
(device.getProductId() == PID_HID) ||
(device.getProductId() == PID_NANOS_LEGACY) ||
(device.getProductId() >> 8 == PID_NANOS) ||
(device.getProductId() == PID_NANOX_LEGACY) ||
(device.getProductId() >> 8 == PID_NANOX) ||
(device.getProductId() >> 8 == PID_NANOS_PLUS) || // Add this
(device.getProductId() == PID_HID_LEDGER_PROTON) ||
(device.getProductId() == PID_HID_LEDGER))) {Testing
Test Environment:
- Device: Ledger Nano S+ (Firmware 2.01)
- App: Bitcoin Legacy
- Android Version: API 36
- Blockstream Green: Development build with fixes applied
Results:
- ✅ Device detected via USB
- ✅ USB permission granted
- ✅ Vendor Specific interface (Interface 1) selected
- ✅ Device recognized as Ledger (
ledger=true) - ✅ APDU communication successful
- ✅ Wallet balance displayed
- ✅ Transaction history loaded
- ✅ Transaction signing
- ❌ Taproot (starting with bc1p) addresses unsupported, I believe it's Bitcoin Legacy Ledger app limitation
Related Issues
- This likely affects all Ledger Nano S+ devices regardless of firmware version
- May also affect future Ledger devices using Vendor Specific USB interface
- Does NOT affect Ledger Nano S, Nano X, or legacy devices (different product IDs)
References
- Ledger USB Protocol Documentation
- Android USB Host Documentation
- USB Vendor ID: 0x2C97 (Ledger)
- USB Product ID: 0x5000 (Nano S+)