summary refs log tree commit diff
path: root/nixos/modules/system/boot/luksroot.nix
diff options
context:
space:
mode:
authorMoritz Maxeiner <moritz@ucworks.org>2014-01-29 17:20:05 +0100
committerMoritz Maxeiner <moritz@ucworks.org>2014-01-29 17:20:05 +0100
commite96f58ef5cdbb28cd4efe1b5f7bc532b9ae55b58 (patch)
tree9cb205bf58b1796ebb0624669282fb5d6bc2d6d6 /nixos/modules/system/boot/luksroot.nix
parent20cfaf0faaef3fe3115275aa64b26b634f0108f0 (diff)
downloadnixlib-e96f58ef5cdbb28cd4efe1b5f7bc532b9ae55b58.tar
nixlib-e96f58ef5cdbb28cd4efe1b5f7bc532b9ae55b58.tar.gz
nixlib-e96f58ef5cdbb28cd4efe1b5f7bc532b9ae55b58.tar.bz2
nixlib-e96f58ef5cdbb28cd4efe1b5f7bc532b9ae55b58.tar.lz
nixlib-e96f58ef5cdbb28cd4efe1b5f7bc532b9ae55b58.tar.xz
nixlib-e96f58ef5cdbb28cd4efe1b5f7bc532b9ae55b58.tar.zst
nixlib-e96f58ef5cdbb28cd4efe1b5f7bc532b9ae55b58.zip
Implement muli-user authentication for yubikey pba, i.e. multiple users can now share a single luks keyslot.
This is achieved by having multiple lines per storage file, one for each user (if the feature is enabled); each of these
lines has the same format as would be the case for the userless authentication, except that they are prepended with a
SHA-512 of the user's id.
Diffstat (limited to 'nixos/modules/system/boot/luksroot.nix')
-rw-r--r--nixos/modules/system/boot/luksroot.nix76
1 files changed, 60 insertions, 16 deletions
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
index b9dc6d7823e0..3f4b703fa9cf 100644
--- a/nixos/modules/system/boot/luksroot.nix
+++ b/nixos/modules/system/boot/luksroot.nix
@@ -68,39 +68,69 @@ let
         mount -t ${yubikey.storage.fsType} ${toString yubikey.storage.device} ${yubikey.storage.mountPoint}
 
         local uuid_r
-        uuid_r="$(take 32 ${yubikey.storage.mountPoint}${yubikey.storage.path})"
-
-        local uuid_luks
-        uuid_luks="$(cryptsetup luksUUID ${device} | take 36 | tr -d '-')"
-
         local k_user
         local challenge
         local k_blob
         local aes_blob_decrypted
         local checksum_correct
         local checksum
+        local uuid_luks
+        local user_record
+
+        uuid_luks="$(cryptsetup luksUUID ${device} | take 36 | tr -d '-')"
+
+        ${optionalString (!yubikey.multiUser) ''
+        user_record="$(cat ${yubikey.storage.mountPoint}${yubikey.storage.path})"
+        uuid_r="$(echo -n $user_record | take 32)"
+        ''}
 
         for try in $(seq 3); do
 
+            ${optionalString yubikey.multiUser ''
+            local user_id
+            echo -n "Enter user id: "
+            read -s user_id
+            echo
+            ''}
+
             ${optionalString yubikey.twoFactor ''
             echo -n "Enter two-factor passphrase: "
             read -s k_user
+            echo
             ''}
 
-            challenge="$(echo -n $k_user$uuid_r$uuid_luks | openssl-wrap dgst -binary -sha1 | rbtohex)"
+            ${optionalString yubikey.multiUser ''
+            local user_id_hash
+            user_id_hash="$(echo -n $user_id | openssl-wrap dgst -binary -sha512 | rbtohex)"
+
+            user_record="$(sed -n -e /^$user_id_hash[^$]*$/p ${yubikey.storage.mountPoint}${yubikey.storage.path} | tr -d '\n')"
 
-            k_blob="$(ykchalresp -${toString yubikey.slot} -x $challenge 2>/dev/null)"
+            if [ ! -z "$user_record" ]; then
+                user_record="$(echo -n $user_record | drop 128)"
+                uuid_r="$(echo -n $user_record | take 32)"
+            ''}
 
-            aes_blob_decrypted="$(drop 32 ${yubikey.storage.mountPoint}${yubikey.storage.path} | hextorb | openssl-wrap enc -d -aes-256-ctr -K $k_blob -iv $uuid_r | rbtohex)"
+                challenge="$(echo -n $k_user$uuid_r$uuid_luks | openssl-wrap dgst -binary -sha1 | rbtohex)"
 
-            checksum="$(echo -n $aes_blob_decrypted | drop 168)"
-            if [ "$(echo -n $aes_blob_decrypted | hextorb | take 84 | openssl-wrap dgst -binary -sha512 | rbtohex)" == "$checksum" ]; then
-                 checksum_correct=1
-                 break
+                k_blob="$(ykchalresp -${toString yubikey.slot} -x $challenge 2>/dev/null)"
+
+                aes_blob_decrypted="$(echo -n $user_record | drop 32 | hextorb | openssl-wrap enc -d -aes-256-ctr -K $k_blob -iv $uuid_r | rbtohex)"
+
+                checksum="$(echo -n $aes_blob_decrypted | drop 168)"
+                if [ "$(echo -n $aes_blob_decrypted | hextorb | take 84 | openssl-wrap dgst -binary -sha512 | rbtohex)" == "$checksum" ]; then
+                    checksum_correct=1
+                    break
+                else
+                    checksum_correct=0
+                    echo "Authentication failed!"
+                fi
+
+            ${optionalString yubikey.multiUser ''
             else
-                 checksum_correct=0
-                 echo "Authentication failed!"
+                checksum_correct=0
+                echo "Authentication failed!"
             fi
+            ''}
         done
 
         if [ "$checksum_correct" != "1" ]; then
@@ -139,8 +169,16 @@ let
             local new_k_blob
             new_k_blob="$(echo -n $new_challenge | hextorb | openssl-wrap dgst -binary -sha1 -mac HMAC -macopt hexkey:$k_yubi | rbtohex)"
 
-            echo -n "$new_uuid_r" > ${yubikey.storage.mountPoint}${yubikey.storage.path}
-            echo -n "$k_yubi$k_luks$checksum" | hextorb | openssl-wrap enc -e -aes-256-ctr -K "$new_k_blob" -iv "$new_uuid_r" | rbtohex >> ${yubikey.storage.mountPoint}${yubikey.storage.path}
+            local new_aes_blob
+            new_aes_blob=$(echo -n "$k_yubi$k_luks$checksum" | hextorb | openssl-wrap enc -e -aes-256-ctr -K "$new_k_blob" -iv "$new_uuid_r" | rbtohex)
+
+            ${optionalString yubikey.multiUser ''
+            sed -i -e "s|^$user_id_hash$user_record|$user_id_hash$new_uuid_r$new_aes_blob|1"
+            ''}
+
+            ${optionalString (!yubikey.multiUser) ''
+            echo -n "$new_uuid_r$new_aes_blob" > ${yubikey.storage.mountPoint}${yubikey.storage.path}
+            ''}
         else
             echo "Warning: Could not obtain new UUID, current challenge persists!"
         fi
@@ -298,6 +336,12 @@ in
               description = "Whether to use a passphrase and a Yubikey (true), or only a Yubikey (false)";
             };
 
+            multiUser = mkOption {
+              default = false;
+              type = types.bool;
+              description = "Whether to allow multiple users to authenticate with a Yubikey";
+            };
+
             slot = mkOption {
               default = 2;
               type = types.int;