Auto-connection request for yubioath-desktop

Yubico Authenticator (yubioath-desktop) communicates with a YubiKey device to create TOTP security codes, among other things. So talking to USB devices is needed, as well as detecting when a device is inserted.

Requesting auto-connection for the following interfaces:

hardware-observe
raw-usb
u2f-devices

These make sense to me and it sounds reasonable for a user installing a yubikey management application to want these auto-connections from the get-go.

+1 as reviewer.

  • Daniel

+1 from me for hardware-observe and u2f-devices - these are both well constrained and logical for this snap. raw-usb is a bit problematic since this provides access to all USB devices on the system and as such is a privileged interface and so I think this would require publisher vetting along the lines of classic confinement. Ideally hidraw (or some other more generic usb interface would exist) and would be supported by hotplug and you could use this on a classic system to provide USB access to particular USB devices designated by vendor + product ID.

However, without this hypothetical interface, raw-usb is the only option for direct access to USB devices on classic systems, so +1 from me for raw-usb as well.

+1 for hardware-observe and u2f-devices.

u2f-devices is supposed to handle access to yubikeys, etc. @dagheyman - can you detail specifically why raw-usb is required? What security denials do you see in the logs if the other two are connected but raw-usb is disconnected?

Some context:
A YubiKey identifies itself over USB in three different ways, and this application uses all them.

  • as a USB-HID device / keyboard.
  • as a smart card reader with a smart card inserted. To use this we bundle our own pcscd daemon, but there might be an interface for this in the future. See Best way to talk to smart cards / pcscd?
  • as a FIDO-HID device. I’m assuming this is what u2f-devices enables.

When removing the raw-usb plug the app can’t connect the to the smartcard reader at all, and snappy-debug says

= AppArmor =
Time: Mar  5 08:16:03
Log: apparmor="DENIED" operation="open" profile="snap.yubioath-desktop.pcscd" name="/dev/bus/usb/001/004" pid=10247 comm="pcscd" requested_mask="wr" denied_mask="wr" fsuid=0 ouid=0
File: /dev/bus/usb/001/004 (write)

There is also a feature in the application where an user defined external smart card reader may be connected over USB, and the YubiKey is then used over NFC. So access to all USB devices may actually be what we need here.

I suspect a change something like this would allow this access, however I am not certain this is the best approach (ie. for each Product/Vendor ID in the u2f-devices interface, add them to the snaps device cgroup whilst allowing via AppArmor r/w access to all USB devices). Since currently for the u2f-devices interface this has not been required I am hesitant to advocate that it be changed in this way, however from a logical point of view, I don’t think it is unexpected that a u2f-devices interface might provide access to the underlying USB device which is providing the U2F device.

@jdstrand I would be keen to get your thoughts on the above proposed change.

Any update on this? Note that I’m happy to drop interfaces at a later stage if for example a smartcard interface would be created (Apple actually have an entitlement for this in their sandbox).

Any update? Or ETA for when a decision may be ready?

I don’t think it is appropriate as it grants more access than what the interface is meant to. raw-usb is currently what we have for this sort of thing for people to fallback on if we don’t have good mediation elsewhere. What would be a better alternative is for snapd to dynamically detect what devices are yubikey devices and use the hotplug mechanism. In this manner, the interfaces grants the precise USB accesses.

Do you have access to one of these devices? How does the device show up in /dev and what does udevadm info /dev/<device> have to say?

I do have access to all supported devices if needed, yes. Here is some example output from a YubiKey 5 with all transports enabled (OTP-HID, FIDO,CCID).

$ dmesg
[647688.818033] usb 1-1: new full-speed USB device number 78 using xhci_hcd
[647688.971663] usb 1-1: New USB device found, idVendor=1050, idProduct=0407, bcdDevice= 5.24
[647688.971669] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[647688.971672] usb 1-1: Product: YubiKey OTP+FIDO+CCID
[647688.971675] usb 1-1: Manufacturer: Yubico
[647688.975797] input: Yubico YubiKey OTP+FIDO+CCID as /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/0003:1050:0407.013E/input/input290
[647689.034654] hid-generic 0003:1050:0407.013E: input,hidraw0: USB HID v1.10 Keyboard [Yubico YubiKey OTP+FIDO+CCID] on usb-0000:00:14.0-1/input0
[647689.035784] hid-generic 0003:1050:0407.013F: hiddev0,hidraw1: USB HID v1.10 Device [Yubico YubiKey OTP+FIDO+CCID] on usb-0000:00:14.0-1/input1
$ udevadm info /dev/hidraw0
P: /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/0003:1050:0407.013E/hidraw/hidraw0
N: hidraw0
L: 0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/0003:1050:0407.013E/hidraw/hidraw0
E: DEVNAME=/dev/hidraw0
E: MAJOR=240
E: MINOR=0
E: SUBSYSTEM=hidraw
E: USEC_INITIALIZED=647686997371
E: ID_SECURITY_TOKEN=1
E: ID_PATH=pci-0000:00:14.0-usb-0:1:1.0
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_1_1_0
E: ID_FOR_SEAT=hidraw-pci-0000_00_14_0-usb-0_1_1_0
E: TAGS=:uaccess:seat:snap_yubikey-manager_ykman:
$ udevadm info /dev/hidraw1
P: /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.1/0003:1050:0407.013F/hidraw/hidraw1
N: hidraw1
L: 0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.1/0003:1050:0407.013F/hidraw/hidraw1
E: DEVNAME=/dev/hidraw1
E: MAJOR=240
E: MINOR=1
E: SUBSYSTEM=hidraw
E: USEC_INITIALIZED=647686995565
E: ID_SECURITY_TOKEN=1
E: ID_PATH=pci-0000:00:14.0-usb-0:1:1.1
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_1_1_1
E: ID_FOR_SEAT=hidraw-pci-0000_00_14_0-usb-0_1_1_1
E: TAGS=:snap_yubikey-manager_ykman:seat:uaccess:

What’s the current state of this request?

This is supported via this stanza: https://github.com/snapcore/snapd/blob/master/interfaces/builtin/u2f_devices.go#L45. The problem (based on the apparmor denial) is that snap.yubioath-desktop.pcscd is not accessing the /dev/hidrawN device as is expected by the interface and is instead accessing /dev/bus/usb/001/004 directly.

@dagheyman - what is the output of:

$ udevadm info /dev/bus/usb/001/004

Note, /dev/bus/usb/001/004 may be unrelated at this point depending on if you rebooted/hotunplugged/hotplugged devices since that denial was posted. It might be easier to disconnect raw-usb, then insert the device and see the device denial from the logs for pcscd and then feeding that into udevadm info.

While I want that information to see if we can improve things in snapd, at this point, +1 for raw-usb.

3 votes for, 0 against for auto-connecting hardware-observe and u2f-devices. 2 votes for, 0 against for auto-connecting raw-usb. Granting auto-connect. These are now live.

snappy-debug with disconnected raw-usb:

= AppArmor =
Time: Mar 31 07:10:21
Log: apparmor="DENIED" operation="open" profile="snap.yubioath-desktop.pcscd" name="/dev/bus/usb/001/018" pid=8509 comm="pcscd" requested_mask="wr" denied_mask="wr" fsuid=0 ouid=0
File: /dev/bus/usb/001/018 (write)

= AppArmor =
Time: Mar 31 07:10:21
Log: apparmor="DENIED" operation="open" profile="snap.yubioath-desktop.pcscd" name="/dev/bus/usb/001/003" pid=8509 comm="pcscd" requested_mask="wr" denied_mask="wr" fsuid=0 ouid=0
File: /dev/bus/usb/001/003 (write)

udevadm:

$ udevadm info /dev/bus/usb/001/018                                                                                                                                                                           
P: /devices/pci0000:00/0000:00:14.0/usb1/1-1                                                                                                                                                                  
N: bus/usb/001/018                                                                                                                                                                                            
L: 0                                                                                                                                                                                                          
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-1                                                                                                                                                          
E: DEVNAME=/dev/bus/usb/001/018                                                                                                                                                                               
E: DEVTYPE=usb_device                                                                                                                                                                                         
E: DRIVER=usb                                                                                                                                                                                                 
E: PRODUCT=1050/407/524                                                                                                                                                                                       
E: TYPE=0/0/0                                                                                                                                                                                                 
E: BUSNUM=001                                      
E: DEVNUM=018                                      
E: MAJOR=189                                       
E: MINOR=17                                        
E: SUBSYSTEM=usb                                   
E: USEC_INITIALIZED=74433569018
E: ID_VENDOR=Yubico                                
E: ID_VENDOR_ENC=Yubico                            
E: ID_VENDOR_ID=1050                               
E: ID_MODEL=YubiKey_OTP+FIDO+CCID
E: ID_MODEL_ENC=YubiKey\x20OTP+FIDO+CCID
E: ID_MODEL_ID=0407                                
E: ID_REVISION=0524                                
E: ID_SERIAL=Yubico_YubiKey_OTP+FIDO+CCID
E: ID_BUS=usb                                      
E: ID_USB_INTERFACES=:030101:030000:0b0000:
E: ID_VENDOR_FROM_DATABASE=Yubico.com
E: ID_MODEL_FROM_DATABASE=Yubikey 4 OTP+U2F+CCID
E: ID_SECURITY_TOKEN=1                             
E: ID_PATH=pci-0000:00:14.0-usb-0:1
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_1
E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_1
E: TAGS=:seat:uaccess:
$ udevadm info /dev/bus/usb/001/003
P: /devices/pci0000:00/0000:00:14.0/usb1/1-3
N: bus/usb/001/003
L: 0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-3
E: DEVNAME=/dev/bus/usb/001/003
E: DEVTYPE=usb_device
E: DRIVER=usb
E: PRODUCT=58f/9540/120
E: TYPE=0/0/0
E: BUSNUM=001
E: DEVNUM=003
E: MAJOR=189
E: MINOR=2
E: SUBSYSTEM=usb
E: USEC_INITIALIZED=2604794
E: ID_VENDOR=Generic
E: ID_VENDOR_ENC=Generic
E: ID_VENDOR_ID=058f
E: ID_MODEL=EMV_Smartcard_Reader
E: ID_MODEL_ENC=EMV\x20Smartcard\x20Reader
E: ID_MODEL_ID=9540
E: ID_REVISION=0120
E: ID_SERIAL=Generic_EMV_Smartcard_Reader
E: ID_BUS=usb
E: ID_USB_INTERFACES=:0b0000:
E: ID_VENDOR_FROM_DATABASE=Alcor Micro Corp.
E: ID_MODEL_FROM_DATABASE=AU9540 Smartcard Reader

So two devices, the first one is the YubiKey, the other one a built in smart card reader in the laptop. I guess pcscd enumerates all available smart card readers when started. Note that this is when just starting the service, not doing anything particular in the app itself.

If you’re interested I could look into sending you a YubiKey device for snapd testing/development, just let me know.

3 votes for, 0 against for auto-connecting hardware-observe and u2f-devices. 2 votes for, 0 against for auto-connecting raw-usb. Granting auto-connect. These are now live.

Great!

Thanks for the offer of the yubikey device, but based on the udevadm, I don’t think that is necessary. There is enough in udevadm info /dev/bus/usb/001/018 for snapd to figure things out I think. See:

...
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-1
E: DEVNAME=/dev/bus/usb/001/018                                                                                                                                                                               
E: DEVTYPE=usb_device                                                                                                                                                                                         
E: DRIVER=usb                                                                                                                                                                                                 
E: PRODUCT=1050/407/524
...
E: ID_VENDOR_ID=1050
...
E: ID_MODEL_ID=0407

The vendor and model ID’s in this output corresponds to the vendor and product in the udev rules in snapd, and we can figure out the path in sysfs and /dev/bus/usb. snapd “just” needs to interrogate the system to map these into the snaps that connect this interface.

Your snap can continue to use raw-usb for this, but now there is a path forward for improving the interface. Thanks!