[Bug 261306] Geli rc.d script does not support insertion of USB devices containing a keyfile.

From: <bugzilla-noreply_at_freebsd.org>
Date: Tue, 18 Jan 2022 13:53:14 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=261306

            Bug ID: 261306
           Summary: Geli rc.d script does not support insertion of USB
                    devices containing a keyfile.
           Product: Base System
           Version: CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: misc
          Assignee: bugs@FreeBSD.org
          Reporter: james@elstone.net

Created attachment 231128
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=231128&action=edit
patch for /etc/rc.d/geli to enable waiting and very early mounting of a USB
storage device

Outline -
==========

The script /etc/rc.d/geli does not support usb flash devices which either have
a  hardware pin or are inserted during system boot process.

This will allow users to have a removable USB device with keyfiles on to be
used by the _user-land_ geli service that is not stored in /boot/ or another
fixed disk on the system. This would allow the security of key management to be
increased.

The attached (git) patch provides a:

1) Pause for a defined number of seconds for the user to insert a predefined
USB storage device.

2) Early mounting of an inserted USB device that contains a keyfile, but just
for geli. This can then be used in the geli_*_flags rcvar as a referenced key
file. The device is unmounted after Geli has used it, so not to impact later
boot stages.


Detail -
========

This is a change to the /etc/rc.d/geli script, see attached diff.

Both the EFI loader and kernel boot process resets all USB devices as they are
enumerated, as expected. If you are using a USB storage device that requires a
manual pin to be entered before it is available (i.e. hardware pin entered on
the USB storage device, e.g. iStorage DataShur) it is very difficult to get a
consistent boot without it erroring and entering single user mode.

This change would also allow the late (prior to geli being called in the init
process) insertion of any USB storage device for keyfile storage purposes. This
would allow a practical end-user mechanism that would increase the system
security as the keyfile is stored on an external and physically separate device
of the users choice.

Each time the USB bus is enumerated the USB device is reset and in effect a pin
based storage device is locked by this, as expected, but cannot be used due to
the time it takes to enter a pin on the device. 


Example Usage -
===============

/etc/rc.conf:
  geli_secdevusb_device="/dev/gpt/security_key"
  geli_secdevusb_path="/security_key"
  geli_secdevusb_wait="120"
  geli_secdevusb_options=""

where:
- "/dev/gpt/security_key" is a gpart label for a UFS partition on a memory
stick, or any other removable device that can be inserted and then mounted
using mount(8).
- /security_keys is a directory that the USB device should be mounted on, and
can be referenced in the geli_*_flags variables in rc.conf.


Setup for testing -
===================
da0 is a fixed disk being encrypted, and da1 is a removable usb storage device
contianing the keyfile. Warning: These test instructions are destructive to the
example devices, read first and adapt for your system; also make sure you have
backed up any critical data encrypted or not for da0 and da1.

#create security key
mkdir /security_key
gpart create -s gpt /dev/da1
gpart add -a 1m -freebsd-ufs -l security_key /dev/da1
newfs /dev/da1p1
mount /dev/gpt/security_key /security_key
mkdir /security_key/geli
dd if=/dev/random of=/security_key/geli/DISK-ID0.key bs=64 count=1

#create encrypted volume with geli
gpart create -s gpt /dev/da0
gpart add -a 1m -freebsd-zfs -l DISK-ID0 /dev/da0
geli init -s 4096 -B none -K "/security_keys/DISK-ID0.key" "/dev/gpt/DISK-ID0"

#update rc.conf variables
sysrc geli_secdevusb_device="/dev/gpt/security_key"
sysrc geli_secdevusb_path="/security_key"
sysrc geli_secdevusb_wait="120"
sysrc geli_secdevusb_options=""
sysrc geli_gpt_DISK_ID0_flags="-k /security_key/geli/DISK-ID0.key"

#remove USB device that is da1 and reboot
reboot

#When prompted inset USB storage device that is da1 and enter the passphrase
used with the geli init command above.


RC Vars -
=========
There are four new RC vars needed:
sysrc geli_secdevusb_device=""
sysrc geli_secdevusb_path=""
sysrc geli_secdevusb_wait=""
sysrc geli_secdevusb_options=""

The default rcvars should be as follows to prevent the code from operating
unless the user requires:
geli_secdevusb_device=""
geli_secdevusb_path=""
geli_secdevusb_wait="0"
geli_secdevusb_options=""


Reasoning
=========

I maybe reinventing the wheel here, but have explored the /boot/loader.conf
vars geli_*_name, and geli_*_flags in /etc/rc.conf, but does not cover this use
case. Most of the examples online refer to putting the keys into /boot/ which
is not a strong security practice IMO as you are storing the key and the
encrypted data in the same machine.

I think this covers a use case not currently supported by FreeBSD, and is an
improvement to have removable keyfiles on a usb device, and would like to help 
other users to reduce their security footprint.

-- 
You are receiving this mail because:
You are the assignee for the bug.