HID: u2fzero: Support NitroKey U2F revision of the device
authorAndrej Shadura <andrew.shadura@collabora.co.uk>
Sat, 23 Oct 2021 14:17:11 +0000 (16:17 +0200)
committerJiri Kosina <jkosina@suse.cz>
Wed, 27 Oct 2021 08:15:55 +0000 (10:15 +0200)
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: Andrej Shadura <andrew.shadura@collabora.co.uk>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-ids.h
drivers/hid/hid-u2fzero.c

index 29564b3..44459be 100644 (file)
 #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
index d70cd3d..7a7a178 100644 (file)
 
 #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);