Open c3Ls1US opened 1 year ago
Still a WIP. Strangely, when recovering the HMAC secret using the library, the value is different than the one recovered via fido2-assert
even after it passes assertion. I have to look into it more later, but you can see this when comparing the hashes. But it could just be that my inputs are wrong, like perhaps the client data hash?
Aug 15 19:01:14 archlinux booster: password from systemd-fido2 token #0 matches Aug 15 19:01:14 archlinux booster: recovered password from systemd-fido2 token #0 Aug 15 19:01:14 archlinux booster: sha256: 1ae2bc586fa456bed4cd6d4f9dc2fc472b1402c268295171e724985ce76ba482 Aug 15 19:01:14 archlinux booster: used fido2-assert to retrieve hmac secret for hidraw1 Aug 15 19:01:14 archlinux booster: running fido2-assert tool for hidraw1 Aug 15 19:01:14 archlinux booster: sha256: 2eaf7579d990625ab8e588892b6fc92c57c9d57fe78d5f8b437bd145d01557e0 Aug 15 19:01:14 archlinux booster: used libfido2 when retrieving hmac secret for hidraw1
Using an existing library for some functionality (e.g. fido2 handling) is a preferable way in general.
The only issue I see here is that libfido will always be linked to booster init
and thus will be always pulled to all images. Given that fido2 functionality is used relatively infrequent I think it makes sense to move it to some optional library that added to the image only when user enables fido2 support.
For this booster needs to move such extra functionality to something like go plugins https://pkg.go.dev/plugin
Using an existing library for some functionality (e.g. fido2 handling) is a preferable way in general.
The only issue I see here is that libfido will always be linked to booster
init
and thus will be always pulled to all images. Given that fido2 functionality is used relatively infrequent I think it makes sense to move it to some optional library that added to the image only when user enables fido2 support.For this booster needs to move such extra functionality to something like go plugins https://pkg.go.dev/plugin
I agree with you, and I'll look into it!
I fixed the bug. At it's current state, only the library's functionality is used rather than fido2-assert
. User presence works, but I haven't tested unlocking with PINs (user verification) yet
I looked into go plugins https://pkg.go.dev/plugin. While extending the libfido2 functionality as a plugin promotes a modular design, thus avoiding the hard dependency to the images, things gets rather complicated. Namely, the CGO runtime will be involved in the init process and reasoning about the program can be more difficult. The plugin maintainers warn about this too:
Reasoning about program initialization is more difficult when some packages may not be initialized until long after the application has started running.
Converting this PR as a draft for now
While extending the libfido2 functionality as a plugin promotes a modular design, thus avoiding the hard dependency to the images, things gets rather complicated.
Bummer.
Are there other ways to decouple libfido2 from the booster? Like compiling booster-libfido2 as a separate binary, invoke it from booster
and use stdin pipe for communication maybe?
Are there other ways to decouple libfido2 from the booster?
I think decoupling will involve either dynamically linking in some other way or compiling as a separate binary like you said. Alternatively, a pure Go library would be great too but there doesn't seem to be any
Like compiling booster-libfido2 as a separate binary, invoke it from
booster
and use stdin pipe for communication maybe?
I could just do that and in some ways, it's better because it involves no additional runtime and dependency. Though, the status quo wouldn't really change since os/exec would still be used and essentially we'd be creating a fido2-assert but more customized/tailored. Still, it may be worth it
@anatol I fixed the bug and was able to get libfido2 to work as a plugin. Now, it needs review
booster.yaml
extra_files: /usr/lib/booster/libfido2_plugin.so
@anatol Finished. I don't plan on adding anything, so let me know if I am missing/or should add anything more.
I also tested (locally) the PIN code path and can confirm it works. However, I haven't tested UV because my key doesn't support it. For Yubikeys, I think the 5 series supports UV but not the security key series (which is what I use).
booster.yaml
extra_files: /usr/lib/booster/libfido2_plugin.so
PKGBUILD:
pkgname=booster-git pkgver=0.11.r58.gde972d3 pkgrel=1 pkgdesc='Fast and secure initramfs generator' arch=(x86_64) url='https://github.com/c3Ls1US/booster' license=(MIT) depends=(bash glibc) makedepends=(git go ruby-ronn-ng libfido2) #checkdepends=(qemu-headless linux tang) optdepends=( 'busybox: to enable emergency shell at the boot time' 'yubikey-personalization: for clevis Yubikey challenge-response support' 'libfido2: for FIDO2 unlocking encrypted partitions enrolled via systemd-cryptenroll' ) backup=(etc/booster.yaml) provides=(booster initramfs) conflicts=(booster) replaces=(booster) source=(git+https://github.com/c3Ls1US/booster.git#branch=fido2) sha512sums=('SKIP') pkgver() { cd booster git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g' } build() { cd booster cd generator CFLAGS="-march=x86-64-v3 -mtune=generic -O2 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection" CGO_CPPFLAGS="${CPPFLAGS}" \ CGO_CFLAGS="${CFLAGS}" \ CGO_CXXFLAGS="${CXXFLAGS}" \ CGO_LDFLAGS="${LDFLAGS}" \ go build -trimpath -buildmode=pie -mod=readonly -modcacherw -ldflags "-linkmode external -extldflags \"${LDFLAGS}\"" # Build the plugin cd ../init/plugins CGO_CPPFLAGS="${CPPFLAGS}" \ CGO_CFLAGS="${CFLAGS}" \ CGO_CXXFLAGS="${CXXFLAGS}" \ CGO_LDFLAGS="${LDFLAGS}" \ CGO_ENABLED=1 go build -buildmode=plugin -o libfido2_plugin.so -trimpath -mod=readonly -modcacherw -ldflags "-linkmode external -extldflags \"${LDFLAGS}\"" libfido2_plugin.go # Move the plugin shared object file mv libfido2_plugin.so ../ # Build init cd .. CGO_CPPFLAGS="${CPPFLAGS}" \ CGO_CFLAGS="${CFLAGS}" \ CGO_CXXFLAGS="${CXXFLAGS}" \ CGO_LDFLAGS="${LDFLAGS}" \ CGO_ENABLED=1 go build -trimpath -buildmode=pie -mod=readonly -modcacherw -ldflags "-linkmode external -extldflags \"${LDFLAGS}\"" cd .. ronn docs/manpage.md } check() { cd booster/tests # arch chroot does not allow access to KVM # TEST_DISABLE_KVM=1 go test -v # integration tests require a lot of time and space to build 10G images } package() { cd booster mkdir "$pkgdir/etc/" touch "$pkgdir/etc/booster.yaml" install -Dp -m755 generator/generator "$pkgdir/usr/bin/booster" install -Dp -m644 docs/manpage.1 "$pkgdir/usr/share/man/man1/booster.1" install -Dp -m755 init/init "$pkgdir/usr/lib/booster/init" install -Dp -m755 init/libfido2_plugin.so "$pkgdir/usr/lib/booster/libfido2_plugin.so" install -Dp -m755 packaging/arch/regenerate_images "$pkgdir/usr/lib/booster/regenerate_images" install -Dp -m644 packaging/arch/90-booster-install.hook "$pkgdir/usr/share/libalpm/hooks/90-booster-install.hook" install -Dp -m755 packaging/arch/booster-install "$pkgdir/usr/share/libalpm/scripts/booster-install" install -Dp -m644 packaging/arch/60-booster-remove.hook "$pkgdir/usr/share/libalpm/hooks/60-booster-remove.hook" install -Dp -m755 packaging/arch/booster-remove "$pkgdir/usr/share/libalpm/scripts/booster-remove" install -Dp -m755 contrib/completion/bash "$pkgdir/usr/share/bash-completion/completions/booster" }
@anatol I'm sorta having second thoughts about this PR to just prefer the current implementation instead, despite it not being pretty
Both accomplish the same effect, but using the library directly seems to add little while adding more complexity--the build process, install size, additional code, CGO--and risks
The last point in particular is a concern, as the init
would be less secure because of the involvement of C code
Uses
libfido2
when validating hidraw devices rather than reading from/sys/class/hidraw
, and more precisely resolves the timing issue for them when recovering the fido2 password from https://github.com/anatol/booster/commit/31d06a47708a139c159cb96dc7dc067a64230db0.It works but still a WIP asfido2-assert
is still used for unlocking here, and I'd favor using the library directly instead