Fork me on GitHub

go-gnulinux

Linux system interfaces in pure Go โ€” reached through /sys, ioctl and ordinary file descriptors, with no libudev, no hidapi and no cgo.

no libudevhidraw ยท sysfs ยท ioctl11 architecturesudev rule named, not guessed100% coverage
zsh
$ go get github.com/go-gnulinux/fido@latest
$ go get github.com/go-gnulinux/factors@latest
One organisation, 2 repositories

libudev is a C library, and it is avoidable. The reference implementation enumerates HID devices through it, which would cost cgo — but udev is used only to list the hidraw nodes, and /sys/class/hidraw already lists them. Everything else libfido2 wants, it parses by hand out of the sysfs uevent file. So that is what happens here, and the result is pure Go on eleven architectures.

The obstacle on Linux is a permission, not an API. /dev/hidraw* belongs to root on a stock system. A package that reported that as “no key found” would send a person to check a cable when the answer is a udev rule, so the two are separate errors and the one that matters names the rule. The same distinction runs all the way up: a factor that could not be asked has not failed, and the policy counts it separately.

The ioctl number is not the same on every architecture, and that is not a detail this org inherited — it is one it nearly got wrong. asm-generic/ioctl.h wraps _IOC_SIZEBITS in an #ifndef, and powerpc and mips override it: thirteen bits instead of fourteen, which moves the direction field down one and changes every request number. A wrong request earns ENOTTY, which would have been reported as not a security key — a real key found, filtered out, never mentioned. Cross-compiling all eleven architectures does not catch it: the arithmetic compiles perfectly and produces the wrong number. Reading the architecture's own header does.

Repositories

Repositories

fido libtransport

v0.1.1

A FIDO security key over hidraw: /sys/class/hidraw enumeration, the uevent file parsed by hand, and the usage page 0xF1D0 read through HIDIOCGRDESC. No libudev, and therefore no cgo.

CI coverage 100%

factors libfactors

v0.1.0

The security key as an mfa.Factor. Almost nothing is here on purpose โ€” asking a key is the same everywhere CTAP is. What stays is what only Linux knows: where a key is, and that one you may not open is not one that refused.

CI coverage 100%

Pure Go with CGO_ENABLED=0, cross-built on the eleven architectures Linux runs on, and held at 100% coverage over everything that needs no hardware. The protocol above these is portable and lives in go-authn/fido; the siblings are go-macos and go-mswin. What has not been done is said plainly: the hidraw half has never run against a key, because the machine this was written on is a Mac. The report-descriptor parser is checked against seventeen real descriptors with IOKit's own verdict as the judge, and none of them is a security key — which is the negative control.