shimunn / fido2luks

Decrypt your LUKS partition using a FIDO2 compatible authenticator
Mozilla Public License 2.0
131 stars 18 forks source link

Fail to unlock device with adapted initcpio hook #43

Open MkfsSion opened 2 years ago

MkfsSion commented 2 years ago

Hello shimunn, I am trying to adapt initcpio hook with fido2luks 0.3.0-alpha version, but I get a strange error with my modfied script.

AuthenticatorError { cause: FidoError(

This operating requires a PIN but none was provided.) }

I have tried to print out the options but --pin option had already been specified. When I am using init shell via appending break parameter to kernel commandline, I can launch the hook via source /init_functions; source /hooks/fido2luks; run_hook; command and it can shows Authenticator PIN: normally and I can input pin to unlock my LUKS volume. Do you have any clue about that?

shimunn commented 2 years ago

The --pin option isn't supposed to be used alone in non interactive mode, but in conjunction with --pin-prefixed like so:

fido2luks open /dev/sda sda-crypt --await-dev 300 --password-helper 'read -rsp "FIDO2 salt for /dev/sda: " passphrase 1>&2 && echo "$passphrase"'  --pin --pin-prefixed

In which case the string(ex. mypin:mypassword) returned by the password helper may be prefixed by an pin which will be used to unlock the authenticator if an pin has been set

MkfsSion commented 2 years ago

Thanks for the information.

MkfsSion commented 2 years ago

Currently, when --pin-prefiexed flag specified, password must be formated as pin:password(plain), but with --salt option, password can be a string: prefixed plain password, file: prefixed filename where password located or a ask string which indicates program to read password through password helper. However, when pin is required, it's seems that the only way to make it work in initcpio hook script is using pin-prefixed format, which means that the password script must handle all the three cases that should be handled by program in the past. So I'd like to ask that if we can do one of the following things to get rid of this:

shimunn commented 2 years ago

Using --pin in interactive mode seems like an suboptiomal solution imo, since that won't work well with distros which use plymouth like fedora. Another solution would be to introduce an --pin-helper analogous to the existing --password-helper which is invoked to query for the pin or maybe the password-helper could be called with pin as first argument in order to signal that a pin instead of the password should be queried.

MkfsSion commented 2 years ago

I agree with the second or third idea, since it's more powerful and I can get rid of ugly tty hack in initcpio script (rpassword library has been hardcoded to use /dev/tty, which is unavailable in ramdisk).

shimunn commented 2 years ago

Okay, I'll get onto that sometime next week

MkfsSion commented 2 years ago

Unfortunately, this does't work too. My initcpio script:

#!/usr/bin/ash

run_hook() {
    modprobe -a -q dm-crypt >/dev/null 2>&1
    . /etc/fido2luks.conf

    if [ -z "$cryptdevice" ]; then
        device="$FIDO2LUKS_DEVICE"
        dmname="$FIDO2LUKS_MAPPER_NAME"
    else
        IFS=: read cryptdev dmname _cryptoptions <<EOF
$cryptdevice
EOF
        if ! device=$(resolve_device "${cryptdev}" ${rootdelay}); then
            return 1
        fi
    fi

    options="--salt $FIDO2LUKS_SALT"

    if [ -n "$FIDO2LUKS_DEVICE_SLOT" ]; then
        options="$options --slot $FIDO2LUKS_DEVICE_SLOT"
    fi

    if [ -n "$FIDO2LUKS_DEVICE_AWAIT" ]; then
        options="$options --await-dev $FIDO2LUKS_DEVICE_AWAIT"
    fi

    printf "\nAuthentication is required to access the $dmname volume at $device\n"

    if [ -n "$FIDO2LUKS_CREDENTIAL_ID" ]; then
        options="$options --creds $FIDO2LUKS_CREDENTIAL_ID"
    fi

    export

    if [ "$FIDO2LUKS_ASK_PIN" == 1 ]; then
        echo "ASk PIN"
        echo -n "Options:"
        echo "$options"
        fido2luks open $device $dmname $options --pin --pin-helper 'read -rsp "Authorizator PIN:" pin; echo $pin;'
    else
        echo "Default"
        echo -n "Options:"
        echo "$options"
        fido2luks open $device $dmname $options
    fi

    exit_code=$?

    if [ $exit_code -ne 0 ]; then
        printf '\n'
        read -s -p 'Press Enter to continue'
        printf '\n'
    fi
}

Runing from initcpio: Screenshot_20220301_144735 Runing manually: Screenshot_20220301_144905

shimunn commented 2 years ago

Are you sure you specified the PIN script correctly? Otherwise the PIN would be empty but not none.

MkfsSion commented 2 years ago

Yes, I am sure. The following are all variables upon the execution of the hook.

CLEANUPHOOKS='udev'
EARLYHOOKS='udev'
FIDO2LUKS_ASK_PIN='1'
FIDO2LUKS_MAX_RETRIES='3'
FIDO2LUKS_SALT='string:secret'
FUNCNAME=''
HOME='/'
HOOKS='udev fido2luks'
HOSTNAME='archlinux'
IFS=' 
'
LATEHOOKS=''
LINENO=''
OPTIND='1'
PATH='/sbin:/usr/sbin:/bin:/usr/bin'
PPID='0'
PS1='\w \$ '
PS2='> '
PS4='+ '
PWD='/'
SHLVL='1'
TERM='linux'
_cryptoptions=''
_rdlog_all='7'
_rdlog_cons='4'
_rdlog_file='1'
_rdlog_kmsg='2'
break='y'
cryptdev='UUID=4a78cce8-5dc0-4e2e-9207-ed48ed074172'
cryptdevice='UUID=4a78cce8-5dc0-4e2e-9207-ed48ed074172:cryptroot'
desc='hook'
device='/dev/vda2'
dmname='cryptroot'
fn='run_hook'
hook='fido2luks'
init='/sbin/init'
initrd='\initramfs-linux.img'
mount_handler='default_mount_handler'
options='--salt string:secret'
rd_logmask='0'
root='LABEL=ArchLinux'
rwopt='rw'
udevd_running='1'