pkgsrc/www/firefox68/patches/patch-dom_webauthn_u2f-hid-rs_src_netbsd_device.rs
riastradh f9cd3ff659 www/firefox68: Add NetBSD support for U2F/FIDO2 security keys.
Based on patch submitted upstream:
https://github.com/mozilla/authenticator-rs/pull/116

Adapted lightly for firefox68 which had its own copy of an older
version of authenticator-rs.
2020-07-15 19:52:23 +00:00

141 lines
4 KiB
Rust

$NetBSD: patch-dom_webauthn_u2f-hid-rs_src_netbsd_device.rs,v 1.1 2020/07/15 19:52:23 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;
+ }
+}