Merge pull request #107402 from ctem/fix/luksroot-master

boot.initrd.luks: add reusePassphrases support for YubiKey 2FA

authored by Guillaume Girol and committed by GitHub 56923181 675969a0

+40 -16
+40 -16
nixos/modules/system/boot/luksroot.nix
··· 56 57 ykinfo -v 1>/dev/null 2>&1 58 if [ $? != 0 ]; then 59 - echo -n "Waiting $secs seconds for Yubikey to appear..." 60 local success=false 61 for try in $(seq $secs); do 62 echo -n . ··· 118 # Cryptsetup locking directory 119 mkdir -p /run/cryptsetup 120 121 - # For Yubikey salt storage 122 mkdir -p /crypt-storage 123 124 ${optionalString luks.gpgSupport '' ··· 218 } 219 220 ${optionalString (luks.yubikeySupport && (yubikey != null)) '' 221 - # Yubikey 222 rbtohex() { 223 ( od -An -vtx1 | tr -d ' \n' ) 224 } ··· 244 local new_k_luks 245 246 mount -t ${yubikey.storage.fsType} ${yubikey.storage.device} /crypt-storage || \ 247 - die "Failed to mount Yubikey salt storage device" 248 249 salt="$(cat /crypt-storage${yubikey.storage.path} | sed -n 1p | tr -d '\n')" 250 iterations="$(cat /crypt-storage${yubikey.storage.path} | sed -n 2p | tr -d '\n')" ··· 254 for try in $(seq 3); do 255 ${optionalString yubikey.twoFactor '' 256 echo -n "Enter two-factor passphrase: " 257 - read -r k_user 258 - echo 259 ''} 260 261 if [ ! -z "$k_user" ]; then ··· 268 269 if [ $? == 0 ]; then 270 opened=true 271 break 272 else 273 opened=false ··· 317 if wait_yubikey ${toString yubikey.gracePeriod}; then 318 do_open_yubikey 319 else 320 - echo "No yubikey found, falling back to non-yubikey open procedure" 321 open_normally 322 fi 323 } ··· 665 yubikey = mkOption { 666 default = null; 667 description = '' 668 - The options to use for this LUKS device in Yubikey-PBA. 669 - If null (the default), Yubikey-PBA will be disabled for this device. 670 ''; 671 672 type = with types; nullOr (submodule { ··· 674 twoFactor = mkOption { 675 default = true; 676 type = types.bool; 677 - description = "Whether to use a passphrase and a Yubikey (true), or only a Yubikey (false)."; 678 }; 679 680 slot = mkOption { 681 default = 2; 682 type = types.int; 683 - description = "Which slot on the Yubikey to challenge."; 684 }; 685 686 saltLength = mkOption { ··· 704 gracePeriod = mkOption { 705 default = 10; 706 type = types.int; 707 - description = "Time in seconds to wait for the Yubikey."; 708 }; 709 710 /* TODO: Add to the documentation of the current module: ··· 779 default = false; 780 type = types.bool; 781 description = '' 782 - Enables support for authenticating with a Yubikey on LUKS devices. 783 See the NixOS wiki for information on how to properly setup a LUKS device 784 - and a Yubikey to work with this feature. 785 ''; 786 }; 787 ··· 799 800 assertions = 801 [ { assertion = !(luks.gpgSupport && luks.yubikeySupport); 802 - message = "Yubikey and GPG Card may not be used at the same time."; 803 } 804 805 { assertion = !(luks.gpgSupport && luks.fido2Support); ··· 807 } 808 809 { assertion = !(luks.fido2Support && luks.yubikeySupport); 810 - message = "FIDO2 and Yubikey may not be used at the same time."; 811 } 812 ]; 813
··· 56 57 ykinfo -v 1>/dev/null 2>&1 58 if [ $? != 0 ]; then 59 + echo -n "Waiting $secs seconds for YubiKey to appear..." 60 local success=false 61 for try in $(seq $secs); do 62 echo -n . ··· 118 # Cryptsetup locking directory 119 mkdir -p /run/cryptsetup 120 121 + # For YubiKey salt storage 122 mkdir -p /crypt-storage 123 124 ${optionalString luks.gpgSupport '' ··· 218 } 219 220 ${optionalString (luks.yubikeySupport && (yubikey != null)) '' 221 + # YubiKey 222 rbtohex() { 223 ( od -An -vtx1 | tr -d ' \n' ) 224 } ··· 244 local new_k_luks 245 246 mount -t ${yubikey.storage.fsType} ${yubikey.storage.device} /crypt-storage || \ 247 + die "Failed to mount YubiKey salt storage device" 248 249 salt="$(cat /crypt-storage${yubikey.storage.path} | sed -n 1p | tr -d '\n')" 250 iterations="$(cat /crypt-storage${yubikey.storage.path} | sed -n 2p | tr -d '\n')" ··· 254 for try in $(seq 3); do 255 ${optionalString yubikey.twoFactor '' 256 echo -n "Enter two-factor passphrase: " 257 + k_user= 258 + while true; do 259 + if [ -e /crypt-ramfs/passphrase ]; then 260 + echo "reused" 261 + k_user=$(cat /crypt-ramfs/passphrase) 262 + break 263 + else 264 + # Try reading it from /dev/console with a timeout 265 + IFS= read -t 1 -r k_user 266 + if [ -n "$k_user" ]; then 267 + ${if luks.reusePassphrases then '' 268 + # Remember it for the next device 269 + echo -n "$k_user" > /crypt-ramfs/passphrase 270 + '' else '' 271 + # Don't save it to ramfs. We are very paranoid 272 + ''} 273 + echo 274 + break 275 + fi 276 + fi 277 + done 278 ''} 279 280 if [ ! -z "$k_user" ]; then ··· 287 288 if [ $? == 0 ]; then 289 opened=true 290 + ${if luks.reusePassphrases then '' 291 + # We don't rm here because we might reuse it for the next device 292 + '' else '' 293 + rm -f /crypt-ramfs/passphrase 294 + ''} 295 break 296 else 297 opened=false ··· 341 if wait_yubikey ${toString yubikey.gracePeriod}; then 342 do_open_yubikey 343 else 344 + echo "No YubiKey found, falling back to non-YubiKey open procedure" 345 open_normally 346 fi 347 } ··· 689 yubikey = mkOption { 690 default = null; 691 description = '' 692 + The options to use for this LUKS device in YubiKey-PBA. 693 + If null (the default), YubiKey-PBA will be disabled for this device. 694 ''; 695 696 type = with types; nullOr (submodule { ··· 698 twoFactor = mkOption { 699 default = true; 700 type = types.bool; 701 + description = "Whether to use a passphrase and a YubiKey (true), or only a YubiKey (false)."; 702 }; 703 704 slot = mkOption { 705 default = 2; 706 type = types.int; 707 + description = "Which slot on the YubiKey to challenge."; 708 }; 709 710 saltLength = mkOption { ··· 728 gracePeriod = mkOption { 729 default = 10; 730 type = types.int; 731 + description = "Time in seconds to wait for the YubiKey."; 732 }; 733 734 /* TODO: Add to the documentation of the current module: ··· 803 default = false; 804 type = types.bool; 805 description = '' 806 + Enables support for authenticating with a YubiKey on LUKS devices. 807 See the NixOS wiki for information on how to properly setup a LUKS device 808 + and a YubiKey to work with this feature. 809 ''; 810 }; 811 ··· 823 824 assertions = 825 [ { assertion = !(luks.gpgSupport && luks.yubikeySupport); 826 + message = "YubiKey and GPG Card may not be used at the same time."; 827 } 828 829 { assertion = !(luks.gpgSupport && luks.fido2Support); ··· 831 } 832 833 { assertion = !(luks.fido2Support && luks.yubikeySupport); 834 + message = "FIDO2 and YubiKey may not be used at the same time."; 835 } 836 ]; 837