| 
					
				 | 
			
			
				@@ -18,6 +18,8 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+CLEVIS_UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # valid_slot() will check whether a given slot is possibly valid, i.e., if it 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # is a numeric value within the specified range. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 valid_slot() { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -63,7 +65,6 @@ clevis_luks_read_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        local CLEVIS_UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         local uuid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # Pattern from luksmeta: active slot uuid. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         read -r _ _ uuid <<< "$(luksmeta show -d "${DEV}" | grep "^${SLT} *")" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -86,7 +87,7 @@ clevis_luks_read_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         local token_id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         token_id=$(cryptsetup luksDump "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     | grep -E -B1 "^\s+Keyslot:\s+${SLT}$" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    | head -n 1 | sed -rn 's|^\s+([0-9]+): clevis|\1|p') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    | sed -n 1p | sed -rn 's|^\s+([0-9]+): clevis|\1|p') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if [ -z "${token_id}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             echo "Cannot load data from ${DEV} slot:${SLT}. No token found!" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return 1 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -111,20 +112,25 @@ clevis_luks_read_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # clevis_luks_used_slots() will return the list of used slots for a given LUKS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # device. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 clevis_luks_used_slots() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    local slots 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local used_slots 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if cryptsetup isLuks --type luks1 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        readarray -t slots < <(cryptsetup luksDump "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            | sed -rn 's|^Key Slot ([0-7]): ENABLED$|\1|p') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! used_slots=$(cryptsetup luksDump "${DEV}" 2>/dev/null \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          | sed -rn 's|^Key Slot ([0-7]): ENABLED$|\1|p'); then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     elif cryptsetup isLuks --type luks2 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        readarray -t slots < <(cryptsetup luksDump "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            | sed -rn 's|^\s+([0-9]+): luks2$|\1|p') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! used_slots=$(cryptsetup luksDump "${DEV}" 2>/dev/null \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          | sed -rn 's|^\s+([0-9]+): luks2$|\1|p'); then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         echo "${DEV} is not a supported LUKS device!" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    echo "${slots[@]}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    echo "${used_slots}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # clevis_luks_decode_jwe() will decode a given JWE. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -132,11 +138,7 @@ clevis_luks_decode_jwe() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     local jwe="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     local coded 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if ! coded=$(jose jwe fmt -i- <<< "${jwe}"); then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    coded=$(jose fmt -j- -g protected -u- <<< "${coded}" | tr -d '"') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    read -r -d . coded <<< "${jwe}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     jose b64 dec -i- <<< "${coded}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -281,3 +283,710 @@ clevis_luks_read_pins_from_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     printf "%s: %s\n" "${SLOT}" "${cfg}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_check_valid_key_or_keyfile() receives a devices and either a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# passphrase or keyfile and then checks whether it is able to unlock the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# device wih the received passphrase/keyfile. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_check_valid_key_or_keyfile() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEY="${2:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEYFILE="${3:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLT="${4:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${KEYFILE}" ] && [ -z "${KEY}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local extra_args 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    extra_args="$([ -n "${SLT}" ] && printf -- '--key-slot %s' "${SLT}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ -n "${KEYFILE}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cryptsetup open --test-passphrase "${DEV}" --key-file "${KEYFILE}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   ${extra_args} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf '%s' "${KEY}" | cryptsetup open --test-passphrase "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                      ${extra_args} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_unlock_device_by_slot() does the unlock of the device and slot 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# passed as parameters and returns the decoded passphrase. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_unlock_device_by_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${SLT}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local jwe passphrase 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! jwe="$(clevis_luks_read_slot "${DEV}" "${SLT}" 2>/dev/null)" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                || [ -z "${jwe}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! passphrase="$(printf '%s' "${jwe}" | clevis decrypt 2>/dev/null)" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                       || [ -z "${passphrase}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clevis_luks_check_valid_key_or_keyfile "${DEV}" "${passphrase}" || return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf '%s' "${passphrase}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_unlock_device() does the unlock of the device passed as 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# parameter and returns the decoded passphrase. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_unlock_device() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local used_slots 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! used_slots=$(clevis_luks_used_slots "${DEV}") \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      || [ -z "${used_slots}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local slt pt 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for slt in ${used_slots}; do 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! pt=$(clevis_luks_unlock_device_by_slot "${DEV}" "${slt}") \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  || [ -z "${pt}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        printf '%s' "${pt}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    done 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_map_device() tries to map the device received as a parameter to a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# block device. As per crypttab(5), we support /path/to/encrypted/blockdev 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# or UUID=<uuid>. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_map_device() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local CDEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [[ "${CDEV}" == UUID=* ]]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        CDEV=/dev/disk/by-uuid/${CDEV#UUID=} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [[ "${CDEV}" == /* ]] && [ -b "${CDEV}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "${CDEV}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      # Invalid crypttab entry. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_is_luks_device_by_uuid_open() checks whether the LUKS device whose 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# UUID was passed as a parameter is already open. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_is_luks_device_by_uuid_open() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local dev_luks_uuid="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${dev_luks_uuid}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dev_luks_uuid="$(echo "${dev_luks_uuid}" | sed -e 's/-//g')" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    test -b /dev/disk/by-id/dm-uuid-*"${dev_luks_uuid}"* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_devices_to_unlock() returns a list of devices to be unlocked, as per 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# the info from crypttab. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_devices_to_unlock() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local list_open_devices="${1:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ ! -r /etc/crypttab ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local dev clevis_devices crypt_device dev_uuid bindings 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clevis_devices= 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Build list of devices to unlock. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    while read -r _ crypt_device _; do 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! dev=$(clevis_map_device "${crypt_device}") \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   || [ -z "${dev}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # Unable to get the device - maybe it's not available, e.g. a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # device on a volume group that has not been activated yet. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # Add it to the list anyway, since it's a pending device. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            clevis_devices="${clevis_devices} ${dev}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # Check if this device has clevis bindings. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! bindings="$(clevis luks list -d "${dev}" 2>/dev/null)" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         || [ -z "${bindings}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if [ -z "${list_open_devices}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # Check if this device is already open. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            dev_uuid="$(cryptsetup luksUUID "${dev}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if clevis_is_luks_device_by_uuid_open "${dev_uuid}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        clevis_devices="${clevis_devices} ${dev}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    done < /etc/crypttab 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    echo "${clevis_devices}" | sed -e 's/^ //' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks1_save_slot() works with LUKS1 devices and it saves a given JWE 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# to a specific device and slot. The last parameter indicates whether we 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# should overwrite existing metadata. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks1_save_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLOT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local JWE="${3}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SHOULD_OVERWRITE="${4:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    luksmeta test -d "${DEV}" || return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if luksmeta load -d "${DEV}" -s "${SLOT}" -u "${CLEVIS_UUID}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        >/dev/null 2>/dev/null; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [ -z "${SHOULD_OVERWRITE}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! luksmeta wipe -f -d "${DEV}" -s "${SLOT}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                           -u "${CLEVIS_UUID}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            echo "Error wiping slot ${SLOT} from ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! echo -n "${JWE}" | luksmeta save -d "${DEV}" -s "${SLOT}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                          -u "${CLEVIS_UUID}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Error saving metadata to LUKSMeta slot ${SLOT} from ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks2_save_slot() works with LUKS2 devices and it saves a given JWE 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# to a specific device and slot. The last parameter indicates whether we 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# should overwrite existing metadata. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks2_save_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLOT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local TKN_ID="${3}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local JWE="${4}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SHOULD_OVERWRITE="${5:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Sanitize clevis LUKS2 tokens. Remove "orphan" clevis tokens, i.e., 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # tokens that are not linked to any key slots. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local token array_len 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for token in $(cryptsetup luksDump "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   | sed -rn 's|^\s+([0-9]+): clevis|\1|p'); do 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # Let's check the length of the "keyslots" array. If zero, it means 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # no key slots are linked, which is a problem. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! array_len=$(cryptsetup token export --token-id \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         "${token}" "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         | jose fmt --json=- --get keyslots --array --length \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         --output=-) || [ "${array_len}" -eq 0 ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # Remove bad token. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            cryptsetup token remove --token-id "${token}" "${DEV}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    done 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! token="$(cryptsetup luksDump "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  | grep -E -B1 "^\s+Keyslot:\s+${SLOT}$" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  | sed -rn 's|^\s+([0-9]+): clevis|\1|p')"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Error trying to read token from LUKS2 device ${DEV}, slot ${SLOT}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ -n "${token}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [ -z "${SHOULD_OVERWRITE}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! cryptsetup token remove --token-id "${token}" "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            echo "Error while removing token ${token} from LUKS2 device ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ -n "${SHOULD_OVERWRITE}" ] && [ -n "${TKN_ID}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cryptsetup token remove --token-id "${TKN_ID}" "${DEV}" 2>/dev/null || : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local metadata 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    metadata=$(printf '{"type":"clevis","keyslots":["%s"],"jwe":%s}' \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               "${SLOT}" "$(jose jwe fmt --input="${JWE}")") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! printf '%s' "${metadata}" | cryptsetup token import \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                $([ -n "${TKN_ID}" ] && printf -- '--token-id %s' "${TKN_ID}") \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Error saving metadata to LUKS2 header in device ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_save_slot() saves a given JWE to a LUKS device+slot. It can also 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# overwrite existing metadata. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_save_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLOT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local TKN_ID="${3}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local JWE="${4}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SHOULD_OVERWRITE="${5:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if cryptsetup isLuks --type luks1 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        clevis_luks1_save_slot "${DEV}" "${SLOT}" "${JWE}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               "${SHOULD_OVERWRITE}" || return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    elif cryptsetup isLuks --type luks2 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        clevis_luks2_save_slot "${DEV}" "${SLOT}" "${TKN_ID}" "${JWE}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               "${SHOULD_OVERWRITE}" || return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks1_backup_dev() backups the LUKSMeta slots from a LUKS device, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# which can be restored with clevis_luks1_restore_dev(). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks1_backup_dev() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local TMP="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${TMP}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    luksmeta test -d "${DEV}" || return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    touch "${TMP}/initialized" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local used_slots slt uuid jwe fname 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! used_slots=$(clevis_luks_used_slots "${DEV}") \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      || [ -z "${used_slots}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for slt in ${used_slots}; do 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! uuid=$(luksmeta show -d "${DEV}" -s "${slt}") \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    || [ -z "${uuid}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! jwe=$(luksmeta load -d "${DEV}" -s "${slt}") \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   || [ -z "${jwe}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fname=$(printf "slot_%s_%s" "${slt}" "${uuid}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        printf "%s" "${jwe}" > "${TMP}/${fname}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    done 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks1_restore_dev() takes care of restoring the LUKSMeta slots from 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# a LUKS device that was backup'ed by clevis_luks1_backup_dev(). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks1_restore_dev() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local TMP="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${TMP}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -e "${TMP}/initialized" ] || return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    luksmeta test -d "${DEV}" || luksmeta init -f -d "${DEV}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local slt uuid jwe fname 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for fname in "${TMP}"/slot_*; do 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [ -f "${fname}" ] || break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! slt=$(echo "${fname}" | cut -d '_' -f 2) \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   || [ -z "${slt}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! uuid=$(echo "${fname}" | cut -d '_' -f 3) \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    || [ -z "${uuid}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! jwe=$(cat "${fname}") || [ -z "${jwe}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! clevis_luks1_save_slot "${DEV}" "${slt}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    "${jwe}" "overwrite"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            echo "Error restoring LUKSmeta slot ${slt} from ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    done 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_backup_dev() backups a particular LUKS device, which can then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# be restored with clevis_luks_restore_dev(). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_backup_dev() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local TMP="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${TMP}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf '%s' "${DEV}" > "${TMP}/device" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf '%s' "${DEV}" > "${TMP}/device" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local HDR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    HDR="${TMP}/$(basename "${DEV}").header" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! cryptsetup luksHeaderBackup "${DEV}" --batch-mode \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            --header-backup-file "${HDR}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Error backing up LUKS header from ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # If LUKS1, we need to manually back up (and later restore) the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # LUKSmeta slots. For LUKS2, simply saving the header also saves 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # the associated tokens. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if cryptsetup isLuks --type luks1 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! clevis_luks1_backup_dev "${DEV}" "${TMP}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_restore_dev() restores a given device that was backup'ed by 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_backup_dev(). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_restore_dev() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local TMP="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${TMP}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -r "${TMP}"/device ] || return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    DEV="$(cat "${TMP}"/device)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local HDR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    HDR="${TMP}/$(basename "${DEV}").header" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ ! -e "${HDR}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "LUKS header backup does not exist" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! cryptsetup luksHeaderRestore "${DEV}" --batch-mode \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            --header-backup-file "${HDR}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Error restoring LUKS header from ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # If LUKS1, we need to manually back up (and later restore) the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # LUKSmeta slots. For LUKS2, simply saving the header also saves 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # the associated tokens. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if cryptsetup isLuks --type luks1 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ! clevis_luks1_restore_dev "${DEV}" "${TMP}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_get_existing_key() may try to recover a valid password from 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# existing bindings and additionally prompt the user for the passphrase. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_get_existing_key() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local PROMPT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local RECOVER="${3:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local pt 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ -n "${RECOVER}" ] && pt="$(clevis_luks_unlock_device "${DEV}")" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                           && [ -n "${pt}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        printf '%s' "${pt}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Let's prompt the user for the password. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    read -r -s -p "${PROMPT}" pt; echo >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Check if key is valid. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clevis_luks_check_valid_key_or_keyfile "${DEV}" "${pt}" || return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf '%s' "${pt}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_luksmeta_sync_fix() makes sure LUKSmeta slots are sync'ed with 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# cryptsetup, in order to prevent issues when saving clevis metadata. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_luksmeta_sync_fix() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${DEV}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # This applies only to LUKS1 devices. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    cryptsetup isLuks --type luks1 "${DEV}" || return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # No issues if the LUKSmeta metadata is not initialized. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    luksmeta test -d "${DEV}" || return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local first_free_slot 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! first_free_slot=$(clevis_luks_first_free_slot "${DEV}") \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                           || [ -z "${first_free_slot}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "There are possibly no free slots in ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # In certain circumstances, we may have LUKSMeta slots "not in sync" with 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # cryptsetup, which means we will try to save LUKSMeta metadata over an 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # already used or partially used slot -- github issue #70. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # If that is the case, let's wipe the LUKSMeta slot here prior to using 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # the LUKSMeta slot. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local lmeta_slot lmeta_status lmeta_uuid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lmeta_slot="$(luksmeta show -d "${DEV}" | grep "^${first_free_slot}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 1   active cb6e8904-81ff-40da-a84a-07ab9ab5715e 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 2 inactive cb6e8904-81ff-40da-a84a-07ab9ab5715e 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lmeta_status="$(echo "${lmeta_slot}" | awk '{print $2}')" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ "${lmeta_status}" != 'inactive' ] && return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lmeta_uuid="$(echo "${lmeta_slot}" | awk '{print $3}')" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ "${lmeta_uuid}" != "${CLEVIS_UUID}" ] && return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    luksmeta wipe -f -d "${DEV}" -s "${first_free_slot}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_add_key() adds a new key to a key slot. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_add_key() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local NEWKEY="${3}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEY="${4}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEYFILE="${5:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${NEWKEY}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${KEY}" ] && [ -z "${KEYFILE}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local extra_args='' input 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    input="$(printf '%s\n%s' "${KEY}" "${NEWKEY}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ -n "${KEYFILE}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        extra_args="$(printf -- '--key-file %s' "${KEYFILE}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        input="$(printf '%s' "${NEWKEY}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf '%s' "${input}" | cryptsetup luksAddKey --batch-mode \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                         --key-slot "${SLT}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                         "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                         ${extra_args} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_update_key() will update a key slot with a new key. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_update_key() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local NEWKEY="${3}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEY="${4}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEYFILE="${5:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${NEWKEY}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Update the key slot with the new key. If we have the key for this slot, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # the change happens in-place. Otherwise, we kill the slot and re-add it. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local in_place 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clevis_luks_check_valid_key_or_keyfile "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           "${KEY}" "${KEYFILE}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           "${SLT}" 2>/dev/null \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           && in_place=true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local input extra_args= 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    input="$(printf '%s\n%s' "${KEY}" "${NEWKEY}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ -n "${KEYFILE}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        extra_args="$(printf -- '--key-file %s' "${KEYFILE}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        input="$(printf '%s' "${NEWKEY}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ -n "${in_place}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        printf '%s' "${input}" | cryptsetup luksChangeKey "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                            --key-slot "${SLT}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                            --batch-mode ${extra_args} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! printf '%s' "${input}" | cryptsetup luksKillSlot "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                          "${SLT}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                          ${extra_args}; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Error wiping slot ${SLT} from ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clevis_luks_add_key "${DEV}" "${SLT}" "${NEWKEY}" "${KEY}" "${KEYFILE}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_save_key_to_slot() will save a new key to a slot. It can either 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# add a new key to a slot or updating an already used slot. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_save_key_to_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local NEWKEY="${3}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEY="${4}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEYFILE="${5:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local OVERWRITE="${6:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${SLT}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${NEWKEY}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Make sure LUKSmeta slots are in sync with cryptsetup, to avoid the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # problem reported in github issue #70. Applies to LUKS1 only. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clevis_luks_luksmeta_sync_fix "${DEV}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Let's check if we are adding a new key or updating an existing one. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local update 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    update="$(clevis_luks_used_slots "${DEV}" | grep "^${SLT}$")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ -n "${update}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # Replace an existing key. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [ -n "${OVERWRITE}" ] || return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        clevis_luks_update_key "${DEV}" "${SLT}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               "${NEWKEY}" "${KEY}" "${KEYFILE}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Add a new key. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clevis_luks_add_key "${DEV}" "${SLT}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        "${NEWKEY}" "${KEY}" "${KEYFILE}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_generate_key() generates a new key for use with clevis. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_generate_key() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local dump filter bits 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dump=$(cryptsetup luksDump "${DEV}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if cryptsetup isLuks --type luks1 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        filter="$(echo "${dump}" | sed -rn 's|MK bits:[ \t]*([0-9]+)|\1|p')" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    elif cryptsetup isLuks --type luks2 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        filter="$(echo -n "${dump}" | \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  sed -rn 's|^\s+Key:\s+([0-9]+) bits\s*$|\1|p')" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    bits="$(echo -n "${filter}" | sort -n | tail -n 1)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pwmake "${bits}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_token_id_by_slot() returns the token ID linked to a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# particular LUKS2 key slot. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_token_id_by_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${SLT}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    cryptsetup isLuks --type luks1 "${DEV}" && echo && return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local tkn_id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tkn_id="$(cryptsetup luksDump "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              | grep -E -B1 "^\s+Keyslot:\s+${SLT}$" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              | sed -rn 's|^\s+([0-9]+): clevis|\1|p')" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf '%s' "${tkn_id}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_cleanup() removes the temporary directory used to store the data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# relevant to device backup and restore. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_cleanup() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${CLEVIS_TMP_DIR}" ] && return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -d "${CLEVIS_TMP_DIR}" ] || return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! rm -rf "${CLEVIS_TMP_DIR}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Deleting temporary files failed!" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "You may need to clean up '${CLEVIS_TMP_DIR}'" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exit 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    unset CLEVIS_TMP_DIR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_first_free_slot() returns the first key slot that is available 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# in a LUKS device. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_first_free_slot() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local first_free_slot 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if cryptsetup isLuks --type luks1 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        first_free_slot=$(cryptsetup luksDump "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          | sed -rn 's|^Key Slot ([0-7]): DISABLED$|\1|p' \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          | sed -n 1p) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    elif cryptsetup isLuks --type luks2 "${DEV}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        local used_slots slt 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        used_slots="$(clevis_luks_used_slots "${DEV}")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for slt in $(seq 0 31); do 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if ! echo "${used_slots}" | grep -q "^${slt}$"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                first_free_slot="${slt}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        done 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Unsupported device ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    echo "${first_free_slot}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# clevis_luks_do_bind() creates or updates a particular binding. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+clevis_luks_do_bind() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local DEV="${1}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local SLT="${2}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local TKN_ID="${3}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local PIN="${4}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local CFG="${5}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local YES="${6:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local OVERWRITE="${7:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEY="${8:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local KEYFILE="${9:-}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${DEV}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${PIN}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${CFG}" ] && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! clevis_luks_check_valid_key_or_keyfile "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                "${KEY}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                "${KEYFILE}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    && ! KEY="$(clevis_luks_get_existing_key "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                "Enter existing LUKS password: " \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                "recover")" || [ -z "${KEY}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local newkey jwe 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! newkey="$(clevis_luks_generate_key "${DEV}")" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   || [ -z "${newkey}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Unable to generate a new key" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Encrypt the new key. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    jwe="$(printf '%s' "${newkey}" | clevis encrypt "${PIN}" "${CFG}" ${YES})" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # We can proceed to binding, after backing up the LUKS header and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # metadata. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    local CLEVIS_TMP_DIR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! CLEVIS_TMP_DIR="$(mktemp -d)" || [ -z "${CLEVIS_TMP_DIR}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Unable to create a a temporary dir for device backup/restore" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    export CLEVIS_TMP_DIR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    trap 'clevis_luks_cleanup' EXIT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # Backup LUKS header. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! clevis_luks_backup_dev "${DEV}" "${CLEVIS_TMP_DIR}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Unable to back up LUKS header from ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if [ -z "${SLT}" ] && ! SLT=$(clevis_luks_first_free_slot "${DEV}") \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  || [ -z "${SLT}" ]; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Unable to find a free slot in ${DEV}" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [ -z "${TKN_ID}" ] && ! TKN_ID="$(clevis_luks_token_id_by_slot "${DEV}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                      "${SLT}")" && return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! clevis_luks_save_key_to_slot "${DEV}" "${SLT}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                      "${newkey}" "${KEY}" "${KEYFILE}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                      "${OVERWRITE}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Unable to save/update key slot; operation cancelled" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        clevis_luks_restore_dev "${CLEVIS_TMP_DIR}" || : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        rm -rf "${CLEVIS_TMP_DIR}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ! clevis_luks_save_slot "${DEV}" "${SLT}" "${tkn_id}" \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               "${jwe}" "${OVERWRITE}"; then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        echo "Unable to update metadata; operation cancelled" >&2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        clevis_luks_restore_dev "${CLEVIS_TMP_DIR}" || : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        rm -rf "${CLEVIS_TMP_DIR}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fi 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    clevis_luks_cleanup 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    trap - EXIT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |