summaryrefslogtreecommitdiff
path: root/security/tor-browser/patches/patch-dom_webauthn_u2f-hid-rs_src_netbsd_device.rs
blob: f7327e74593c96d1b1d4fb13e0b2ecfcb43ead0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
$NetBSD: patch-dom_webauthn_u2f-hid-rs_src_netbsd_device.rs,v 1.1 2020/08/17 06:58:32 riastradh Exp $

Add NetBSD support for U2F.

--- dom/webauthn/u2f-hid-rs/src/netbsd/device.rs.orig	2020-07-15 16:19:08.142403669 +0000
+++ dom/webauthn/u2f-hid-rs/src/netbsd/device.rs
@@ -0,0 +1,134 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+extern crate libc;
+
+use std::mem;
+use std::io::Read;
+use std::io::Write;
+use std::io;
+
+use consts::CID_BROADCAST;
+use consts::HID_RPT_SIZE;
+use platform::fd::Fd;
+use platform::uhid;
+use u2ftypes::U2FDevice;
+use util::io_err;
+
+#[derive(Debug)]
+pub struct Device {
+    fd: Fd,
+    cid: [u8; 4],
+}
+
+impl Device {
+    pub fn new(fd: Fd) -> io::Result<Self> {
+        Ok(Self { fd, cid: CID_BROADCAST })
+    }
+
+    pub fn is_u2f(&mut self) -> bool {
+        if !uhid::is_u2f_device(&self.fd) {
+            return false;
+        }
+        // This step is not strictly necessary -- NetBSD puts fido
+        // devices into raw mode automatically by default, but in
+        // principle that might change, and this serves as a test to
+        // verify that we're running on a kernel with support for raw
+        // mode at all so we don't get confused issuing writes that try
+        // to set the report descriptor rather than transfer data on
+        // the output interrupt pipe as we need.
+        match uhid::hid_set_raw(&self.fd, true) {
+            Ok(_) => (),
+            Err(_) => return false,
+        }
+        if let Err(_) = self.ping() {
+            return false;
+        }
+        true
+    }
+
+    fn ping(&mut self) -> io::Result<()> {
+        for i in 0..10 {
+            let mut buf = vec![0u8; 1 + HID_RPT_SIZE];
+
+            buf[0] = 0;         // report number
+            buf[1] = 0xff;      // CID_BROADCAST
+            buf[2] = 0xff;
+            buf[3] = 0xff;
+            buf[4] = 0xff;
+            buf[5] = 0x81;      // ping
+            buf[6] = 0;
+            buf[7] = 1;         // one byte
+
+            self.write(&buf[..])?;
+
+            // Wait for response
+            let mut pfd: libc::pollfd = unsafe { mem::zeroed() };
+            pfd.fd = self.fd.fileno;
+            pfd.events = libc::POLLIN;
+            let nfds = unsafe { libc::poll(&mut pfd, 1, 100) };
+            if nfds == -1 {
+                return Err(io::Error::last_os_error());
+            }
+            if nfds == 0 {
+                debug!("device timeout {}", i);
+                continue;
+            }
+
+            // Read response
+            self.read(&mut buf[..])?;
+
+            return Ok(());
+        }
+
+        Err(io_err("no response from device"))
+    }
+}
+
+impl PartialEq for Device {
+    fn eq(&self, other: &Device) -> bool {
+        self.fd == other.fd
+    }
+}
+
+impl Read for Device {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let bufp = buf.as_mut_ptr() as *mut libc::c_void;
+        let nread = unsafe { libc::read(self.fd.fileno, bufp, buf.len()) };
+        if nread == -1 {
+            return Err(io::Error::last_os_error());
+        }
+        Ok(nread as usize)
+    }
+}
+
+impl Write for Device {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        // Always skip the first byte (report number)
+        let data = &buf[1..];
+        let data_ptr = data.as_ptr() as *const libc::c_void;
+        let nwrit = unsafe {
+            libc::write(self.fd.fileno, data_ptr, data.len())
+        };
+        if nwrit == -1 {
+            return Err(io::Error::last_os_error());
+        }
+        // Pretend we wrote the report number byte
+        Ok(nwrit as usize + 1)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl U2FDevice for Device {
+    fn get_cid<'a>(&'a self) -> &'a [u8; 4] {
+        &self.cid
+    }
+
+    fn set_cid(&mut self, cid: [u8; 4]) {
+        self.cid = cid;
+    }
+}