Commit 6748031a authored by Andrej Shadura's avatar Andrej Shadura Committed by Jiri Kosina
Browse files

HID: u2fzero: Support NitroKey U2F revision of the device

NitroKey produced a clone of U2F Zero with a different firmware,
which moved extra commands into the vendor range.
Disambiguate hardware revisions and select the correct configuration in
u2fzero_probe.

Link: https://github.com/Nitrokey/nitrokey-fido-u2f-firmware/commit/a93c16b41f


Signed-off-by: default avatarAndrej Shadura <andrew.shadura@collabora.co.uk>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 42d43c92
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -288,6 +288,9 @@
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020	0x0020
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040	0x0040

#define USB_VENDOR_ID_CLAY_LOGIC	0x20a0
#define USB_DEVICE_ID_NITROKEY_U2F	0x4287

#define USB_VENDOR_ID_CMEDIA		0x0d8c
#define USB_DEVICE_ID_CM109		0x000e
#define USB_DEVICE_ID_CMEDIA_HS100B	0x0014
+36 −9
Original line number Diff line number Diff line
@@ -26,6 +26,30 @@

#define HID_REPORT_SIZE		64

enum hw_revision {
	HW_U2FZERO,
	HW_NITROKEY_U2F,
};

struct hw_revision_config {
	u8 rng_cmd;
	u8 wink_cmd;
	const char *name;
};

static const struct hw_revision_config hw_configs[] = {
	[HW_U2FZERO] = {
		.rng_cmd  = 0x21,
		.wink_cmd = 0x24,
		.name = "U2F Zero",
	},
	[HW_NITROKEY_U2F] = {
		.rng_cmd  = 0xc0,
		.wink_cmd = 0xc2,
		.name = "NitroKey U2F",
	},
};

/* We only use broadcast (CID-less) messages */
#define CID_BROADCAST		0xffffffff

@@ -52,10 +76,6 @@ struct u2f_hid_report {

#define U2F_HID_MSG_LEN(f)	(size_t)(((f).init.bcnth << 8) + (f).init.bcntl)

/* Custom extensions to the U2FHID protocol */
#define U2F_CUSTOM_GET_RNG	0x21
#define U2F_CUSTOM_WINK		0x24

struct u2fzero_device {
	struct hid_device	*hdev;
	struct urb		*urb;	    /* URB for the RNG data */
@@ -67,6 +87,7 @@ struct u2fzero_device {
	u8			*buf_in;
	struct mutex		lock;
	bool			present;
	kernel_ulong_t		hw_revision;
};

static int u2fzero_send(struct u2fzero_device *dev, struct u2f_hid_report *req)
@@ -154,7 +175,7 @@ static int u2fzero_blink(struct led_classdev *ldev)
		.report_type = 0,
		.msg.cid = CID_BROADCAST,
		.msg.init = {
			.cmd = U2F_CUSTOM_WINK,
			.cmd = hw_configs[dev->hw_revision].wink_cmd,
			.bcnth = 0,
			.bcntl = 0,
			.data  = {0},
@@ -182,7 +203,7 @@ static int u2fzero_rng_read(struct hwrng *rng, void *data,
		.report_type = 0,
		.msg.cid = CID_BROADCAST,
		.msg.init = {
			.cmd = U2F_CUSTOM_GET_RNG,
			.cmd = hw_configs[dev->hw_revision].rng_cmd,
			.bcnth = 0,
			.bcntl = 0,
			.data  = {0},
@@ -295,6 +316,8 @@ static int u2fzero_probe(struct hid_device *hdev,
	if (dev == NULL)
		return -ENOMEM;

	dev->hw_revision = id->driver_data;

	dev->buf_out = devm_kmalloc(&hdev->dev,
		sizeof(struct u2f_hid_report), GFP_KERNEL);
	if (dev->buf_out == NULL)
@@ -329,7 +352,7 @@ static int u2fzero_probe(struct hid_device *hdev,
		return ret;
	}

	hid_info(hdev, "U2F Zero LED initialised\n");
	hid_info(hdev, "%s LED initialised\n", hw_configs[dev->hw_revision].name);

	ret = u2fzero_init_hwrng(dev, minor);
	if (ret) {
@@ -337,7 +360,7 @@ static int u2fzero_probe(struct hid_device *hdev,
		return ret;
	}

	hid_info(hdev, "U2F Zero RNG initialised\n");
	hid_info(hdev, "%s RNG initialised\n", hw_configs[dev->hw_revision].name);

	return 0;
}
@@ -357,7 +380,11 @@ static void u2fzero_remove(struct hid_device *hdev)

static const struct hid_device_id u2fzero_table[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL,
	  USB_DEVICE_ID_U2F_ZERO) },
	  USB_DEVICE_ID_U2F_ZERO),
	  .driver_data = HW_U2FZERO },
	{ HID_USB_DEVICE(USB_VENDOR_ID_CLAY_LOGIC,
	  USB_DEVICE_ID_NITROKEY_U2F),
	  .driver_data = HW_NITROKEY_U2F },
	{ }
};
MODULE_DEVICE_TABLE(hid, u2fzero_table);