2

I am building an Android authenticator for FIDO2. I got stuck with read/write characteristics. I am working on Mac - Chrome 75. Chrome can detect my Android BLE authenticator. After detecting my BLE Authenticator, onCharacteristicReadRequest() is called from authenticator side. Inside the onCharacteristicReadRequest() I am using the code written below but there is no response from client after that.

I have tried U2F with version 0b01000000. It's working fine. When I moved FIDO2 version 0b100000, I am facing this issue. I am advertising fido service and device info service from authenticator. Both services has been added with Thread.sleep(1000) interval. I couldn't add both services sequentially. When I add both services sequentially, I am getting ArrayIndexOutofBoundException.

I don't know if both issues are interlinked. Please correct me if I am doing anything wrong.

{
...
}else if (characteristic.getUuid().equals(FidoUUIDConstants.FIDO_SERVICE_REVISION_BITFIELD)) {
    status = BluetoothGatt.GATT_SUCCESS;
    ByteBuffer bb = ByteBuffer.allocate(1);
    bb.order(ByteOrder.BIG_ENDIAN);
    bb.put((byte) (1 << 5));
    bytes = bb.array();
}
mGattServer.sendResponse(device, requestId, status, 0, bytes);

Client should read/write characteristics after fidoServiceBitFieldversion is expected.

ahsanali274
  • 471
  • 2
  • 14
Chella M
  • 392
  • 1
  • 2
  • 15
  • so what is the question? – Bao HQ Jun 12 '19 at 04:24
  • I am getting onMtuChanged() callback with mtu=104 and onCharacteristicReadRequest(). After that I am not getting any read/write characteristics callback. Is there any issue with my implementation? – Chella M Jun 12 '19 at 07:03
  • read/write requests come when there is a bluetooth central device communicate with your authenticator app. – Bao HQ Jun 12 '19 at 07:39
  • onCharacteristicReadRequest() is getting called where I am writing "bytes = new byte[] {0x20}; gattServer.sendResponse(device, requestId, status, 0, bytes);" for fidoServiceRevisionBitfield characteristics. After that I am not getting any callback. webauthn.io can identify my peripheral device. – Chella M Jun 12 '19 at 07:43
  • Ensure you are no longer providing the deprecated `fidoServiceRevision` characteristic – James Westgate Nov 06 '20 at 09:50

3 Answers3

2

I couldn't add both services sequentially

I think you could add the device info service like the following:

gattServer = bleManager.openGattServer(this, new BluetoothGattServerCallback() {
    @Override
    public void onServiceAdded(int status, BluetoothGattService service) {
        if (service.getUuid().equals(FidoUUIDConstants.FIDO2_GATT_SERVICE)) {
            gattServer.addService(deviceInfoService);
        }
    }
});
gattServer.addService(fido2GattService)

For the characteristic fidoServiceRevisionBitfield, I just simply followed this statement a device that only supports FIDO2 Rev 1 will only have a fidoServiceRevisionBitfield characteristic of length 1 with value 0x20. at index 8.3.5.1. FIDO Service of CTAP document. Hence, my implementation was:

if(characteristic.getUuid().equals(FIDO2GattService.SERVICE_REVISION_BITFIELD)) {
    status = BluetoothGatt.GATT_SUCCESS;
    bytes = new byte[] {0x20}
}
gattServer.sendResponse(device, requestId, status, 0, bytes);
Huong
  • 107
  • 2
  • 10
  • I did the same "bytes = new byte[] {0x20}" already. It's not working. I am getting onMtuChanged() with mtu 104 and onCharacteristicReadRequest(). After that I am not getting any callback. Is there any chance for some other issue? – Chella M Jun 12 '19 at 07:00
2

You should override all the methods of BluetoothGattServerCallback

I think you are missing onDescriptorReadRequest, onDescriptorWriteRequest implements.

@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
    if (descriptor.getCharacteristic().getUuid().equals(FIDO2GattService.CONTROL_POINT_UUID) &&
            descriptor.getUuid().equals(FIDO2GattService.CONTROL_POINT_DESCRIPTOR_UUID)) {
        gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, new byte[] {0x31, 0x2e, 0x32});
    } else {
        gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, new byte[] {0x00, 0x00});
    }
}
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
    gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
}
Bao HQ
  • 1,145
  • 7
  • 18
  • Thanks for the response Boa. I am getting callback on onDescriptorReadRequest(). But not in onDescriptorReadRequest(). I have the Fido status descriptor details. I don't know about control point descriptor. Is there any link? – Chella M Jun 13 '19 at 07:23
2

I agreed with @Bao's concern. According to CTAP specification, you should define descriptor corresponding to each characteristic with READ/WRITE permission. Note that the UUIDs for each descriptor are needed a valid UUID 128-bit format. All descriptors have both permissions READ and WRITE. For example:

UUID CONTROL_POINT_DESCRIPTOR_UUID = UUID.fromString("00002901-0000-1000-8000-00805f9b34fb");
BluetoothGattDescriptor controlPointDescriptor = new BluetoothGattDescriptor(
    CONTROL_POINT_DESCRIPTOR_UUID,
    BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE
);
Huong
  • 107
  • 2
  • 10