File disk-encryption-tool-1+git20240704.5a6539c.obscpio of Package disk-encryption-tool

07070100000000000081A4000000000000000000000001668640820000013B000000000000000000000000000000000000003900000000disk-encryption-tool-1+git20240704.5a6539c/.editorconfig# EditorConfig configuration for sdbootutil
# http://EditorConfig.org

# Top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file, utf-8 charset
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = tab
indent_size = 8
07070100000001000081A4000000000000000000000001668640820000042E000000000000000000000000000000000000003300000000disk-encryption-tool-1+git20240704.5a6539c/LICENSEMIT License

Copyright (c) 2023 Ludwig Nussel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
07070100000002000081A400000000000000000000000166864082000006DC000000000000000000000000000000000000003500000000disk-encryption-tool-1+git20240704.5a6539c/README.mdTool to turn a plain text image into one using LUKS full disk
encryption. There are three modes:

* Directly encrypt a disk image on a host system. The image can then
  be deployed somewhere else
* Prime a disk image by adding code to the initrd of the image that
  encrypts the image on first boot
* Include the initrd code already when building an image. The image
  would then encrypt itself on first boot.

In general the tool is developed with [kiwi](https://github.com/OSInside/kiwi)
in mind. It assumes that the image contains a single root fs using btrfs in the
third partition. Both grub2 and systemd-boot are supported. The tool generates
a

Example to directly encrypt an image:

    disk-encryption-tool -v SLE-Micro.x86_64-5.4.0-Default-GM.raw

Example to prime a plain text image to encrypt on first boot:

    disk-encryption-tool -v --prime SLE-Micro.x86_64-5.4.0-Default-GM.raw


When run on first boot the tool integrates with
[jeos-firstboot](https://github.com/openSUSE/jeos-firstboot/). The encryption
in initrd deploys an automatically generated recovery key, compatible with
[systemd-cryptenroll](https://www.freedesktop.org/software/systemd/man/latest/systemd-cryptenroll.html).
Later in the real root a jeos-firsboot module then offers to deploy
either the root password or another custom passphrase as well.

Parameters for cryptsetup-reencrypt(8) can be passed via
`/etc/encrypt_options`. One option per line, e.g.

   --type=luks1
   --iter-time=2000

It's also possible to integrate with combustion. The combustion
script would have to look like this:

    #!/bin/bash
    # combustion: prepare
    if [ "$1" = "--prepare" ]; then
        echo 12345 | disk-encryption-tool -v
    else
        echo root:12345 | chpasswd
    fi
07070100000003000081ED0000000000000000000000016686408200003003000000000000000000000000000000000000004000000000disk-encryption-tool-1+git20240704.5a6539c/disk-encryption-tool#!/bin/bash
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: Copyright 2023 SUSE LLC
set -e
shopt -s nullglob

unset "${!LC_@}"
LANG="C.utf8"
export LANG

verbose=
prime=
gen_key=

switched_rw=
cr_name='cr_root'
cr_dev=
blkdev=
blkpart=
partno=
mp=
mounted=
tmpdir=$(mktemp -d -t disk-encryption-tool.XXXXXX)
cleanup()
{
	set +e
	if [ -n "$mp" ]; then
		while read -r i; do
			[ "$i" != "$mp" ] || make_ro
			umount "$i"
		done < <(findmnt -o TARGET -Rn --list "$mp" | tac)
	fi
	if [ -n "$mounted" ]; then
		if [ -e "$tmpdir/mounts" ]; then
			# restore previous mounts
			while read -r line; do
				eval "$line"
				mapfile -td, options < <(echo -n "$OPTIONS")
				if [ -n "$cr_dev" ] && [ "$SOURCE" = "$blkpart" ]; then
					SOURCE="$cr_dev"
				fi
				mount "$SOURCE" "$TARGET" -t "$FSTYPE" -o "$OPTIONS"
			done < "$tmpdir/mounts"
		fi
	else
		[ -e "$cr_dev" ] && cryptsetup close "${cr_dev##*/}"
		case "$blkdev" in
			/dev/nbd*) qemu-nbd -d "$blkdev" ;;
			/dev/loop*) losetup -d "$blkdev" ;;
		esac
	fi
	[ -d "$tmpdir" ] && ! mountpoint -q "$tmpdir/mnt" && rm -rf "$tmpdir"
}
trap cleanup EXIT

helpandquit()
{
	cat <<-EOF
		Usage: $0 [OPTIONS] IMAGE|BLOCKDEV

		Encrypt IMAGE or BLOCKDEV

		OPTIONS:
		  --verbose       verbose
		  --prime         add hook scripts to initrd to encrypt on first boot
		  --partno=N      partition number (default 3)
		  --gen-key       generate random recovery key
		  -h              help screen

	EOF
	exit 0
}

log_info()
{
	[ "${verbose:-0}" -gt 0 ] || return 0
	echo "$@"
}

err()
{
	echo "Error: $*" >&2
	exit 1
}

warn()
{
	echo "Warning: $*" >&2
}

isdigits()
{
       local v="${1:?}"
       [ -z "${v//[0-9]*/}" ]
}

settle_umount_events()
{
        # Manual umount confuses systemd sometimes because it's async and the
        # .mount unit might still be active when the "start" is queued, making
        # it a noop, which ultimately leaves /sysroot unmounted
        # (https://github.com/systemd/systemd/issues/20329). To avoid that,
        # wait until systemd processed the umount events. In a chroot (or with
        # SYSTEMD_OFFLINE=1) systemctl always succeeds, so avoid an infinite loop.
	if [ "$mounted" = "/sysroot" ] && ! systemctl --quiet is-active does-not-exist.mount; then
		while systemctl --quiet is-active sysroot.mount; do sleep 0.5; done
	fi
}

read_password()
{
	local password2
	[ -z "$password" ] || return 0
	if ! [ -t 0 ]; then
		read -r -s password
		return "$?"
	fi
        while true; do
                read -r -s -p "Enter encryption passphrase: " password
		echo
		if type -p pwscore &>/dev/null; then
			echo "$password" | pwscore || continue
		fi
                read -r -s -p "Confirm encryption passphrase: " password2
		echo
                if [ "$password" != "$password2" ]; then
                        echo "Entered passwords don't match"
                        continue
                fi
                [ -n "$password" ] || err "No password, no encryption"
                break
        done
}

encrypt()
{
	local encrypt_options=(\
		--reduce-device-size 32m \
		--progress-frequency=1 \
	)
	if [ -e "${ENCRYPTION_CONFIG:-/etc/encrypt_options}" ]; then
		while read -r op; do
			[ "${op//#}" = "$op" ] || continue
			encrypt_options+=("$op")
		done < "${ENCRYPTION_CONFIG:-/etc/encrypt_options}"
	fi
	# sle 15 compat code
	if type -p cryptsetup-reencrypt &> /dev/null; then
		read_password

		echo "$password" | cryptsetup-reencrypt --new --type luks1 "${encrypt_options[@]}" "$@" "${blkpart}"

		log_info "Encryption done"

		log_info "open encrypted image"
		echo "$password" | cryptsetup open "${blkpart}" "$cr_name"
	else
		log_info "encrypt with options ${encrypt_options[*]}"
		if [ -n "$password" ]; then
			# XXX: hopefully we can use the kernel keyring in the future here
			cryptsetup reencrypt --force-password --verbose --encrypt "${encrypt_options[@]}" "$@" "${blkpart}" "$cr_name" <<<"$password"
			[ -z "$gen_key" ] ||  echo '{"type":"systemd-recovery","keyslots":["0"]}' | cryptsetup token import "${blkpart}"
		else
			cryptsetup reencrypt --batch-mode --verify-passphrase --force-password --verbose --encrypt "${encrypt_options[@]}" "$@" "${blkpart}" "$cr_name"
		fi
	fi
	cr_dev="/dev/mapper/$cr_name"
}

call_dracut()
{
	if [ -L "$mp/boot/initrd" ]; then
		local initrd kv
		initrd="$(readlink "$mp/boot/initrd")"
		kv="${initrd#initrd-}"
		log_info "create initrd for $kv"
		chroot "$mp" dracut --add-drivers dm_crypt -q -f "/boot/$initrd" "$kv" "$@"
	elif [ -e "$mp/etc/kernel/entry-token" ]; then
		local token kernel kv
		read -r token < "$mp/etc/kernel/entry-token"
		log_info "token $token"
		for initrd in "$mp/boot/efi/$token"/*/initrd-*; do
			kv="${initrd%/*}"
			kv="${kv##*/}"
			initrd="${initrd#"$mp"}"
			log_info "create $initrd for $kv"
			hostonly_l=no chroot "$mp" dracut -q --reproducible -f "$initrd" "$kv" "$@"
		done
	else
		err "Unsupported boot loader or fs layout"
	fi
}

mountstuff()
{
	mount -t tmpfs -o size=10m tmpfs "$mp/run"
	for i in proc dev sys; do
		mount --bind "/$i" "$mp/$i"
	done

	for i in /.snapshots /boot/efi /boot/writable /var; do
		grep -q "\s$i\s" "$mp/etc/fstab" || continue
		[ -d "$mp/$i" ] || continue
		mountpoint -q "$mp/$i" && continue
		mount -T "$mp"/etc/fstab --target-prefix="$mp" "/$i"
	done
}

make_rw()
{
	local prop
	read -r prop < <(btrfs prop get -t s "$mp" ro)
	[ "$prop" = "ro=true" ] || return 0
	log_info "switch to rw"
	btrfs prop set -t s "$mp" ro false
	switched_rw=1
}

make_ro()
{
	[ -n "$switched_rw" ] || return 0
	unset switched_rw
	log_info "set ro again"
	btrfs prop set -t s "$mp" ro true
}

####### main #######

getopttmp=$(getopt -o hv --long help,verbose,prime,partno:,gen-key -n "${0##*/}" -- "$@")
eval set -- "$getopttmp"

while true ; do
        case "$1" in
                -h|--help) helpandquit ;;
		-v|--verbose) verbose=$((++verbose)); shift ;;
		--prime) prime="1"; shift ;;
		--partno) partno="$2"; shift 2;;
		--gen-key) gen_key="1"; shift;;
                --) shift ; break ;;
                *) echo "Internal error!" ; exit 1 ;;
        esac
done

[ -z "$1" ] && [ -e /etc/initrd-release ] && set -- /sysroot

[ -n "$1" ] || helpandquit

[ -z "$prime" ] && [ -e "/dev/mapper/$cr_name" ] && err "$cr_name exists. Exit."

if [ -d "$1" ] || [ -b "$1" ]; then
	if [ -b "$1" ]; then
		blkpart="$1"
	else
		mountpoint -q "$1" || err "$1 is not a valid mountpoint"
		mp="$1"
		mounted="$1"
		blkpart="$(findmnt -nvo SOURCE "$mp")"
	fi
	[ -L "/sys/class/block/${blkpart##*/}" ] || err "$blkpart is not a partition"
	blkdev="$(readlink -f "/sys/class/block/${blkpart##*/}")"
	blkdev="${blkdev%/*}"
	blkdev="/dev/${blkdev##*/}"
	read -r partno < "/sys/class/block/${blkpart##*/}"/partition
else
	[ -n "$partno" ] || warn "--partno not specified, assuming 3"
	: "${partno:=3}"
	case "${1##*/}" in
		*.raw )
			log_info "setting up loop device"
			blkdev="$(losetup --show -fP "$1")"
			log_info "loop device $blkdev"
			;;
		*.qcow2)
			[ -e "/dev/nbd0" ] || modprobe nbd
			blkdev=/dev/nbd0
			qemu-nbd -c "$blkdev" "$1"
			udevadm settle
			;;
		*) err "Unsupported image" ;;
	esac
	blkpart="${blkdev}p${partno}"
fi
shift

eval "$(blkid -c /dev/null -o export "$blkpart"|sed 's/^/loop_/')"

[ "$loop_TYPE" != crypto_LUKS ] || { echo "Already encrypted"; exit 0; }
[ "$loop_TYPE" = btrfs ] || err "File system is ${loop_TYPE:-unknown} but only btrfs is supported"

if [ -z "$mounted" ]; then
	log_info "mounting fs"
	mkdir -p "$tmpdir/mnt"
	mount -t btrfs -o rw "${blkpart}" "$tmpdir/mnt"
	mp="$tmpdir/mnt"
else
	mountpoint -q "$mp" || err "$mp is not mounted"
	findmnt -o SOURCE,TARGET,FSTYPE,OPTIONS -Rvn --pairs "$mp" > "$tmpdir/mounts"
	mount -o remount,rw "$mp"
fi

if [ -n "$prime" ]; then
	mkdir -p "$tmpdir/overlay-w"
	dst="$tmpdir/overlay/95disk-encryption-tool"
	mkdir -p "$dst"
	for i in disk-encryption-tool disk-encryption-tool-dracut module-setup.sh \
			disk-encryption-tool-dracut.service generate-recovery-key; do
		cp "${0%/*}/$i" "$dst/$i"
	done
	if [ -e "${ENCRYPTION_CONFIG:-/etc/encrypt_options}" ]; then
		cp "${ENCRYPTION_CONFIG:-/etc/encrypt_options}" "$dst/encrypt_options"
		export ENCRYPTION_CONFIG="/usr/lib/dracut/modules.d/95disk-encryption-tool/encrypt_options"
	fi

	make_rw

	mountstuff

	# dirty
	if [ -d "$mp/usr/share/jeos-firstboot/modules" ]; then
		install -D -m 644 "${0%/*}/jeos-firstboot-diskencrypt-override.conf" "$mp/usr/lib/systemd/system/jeos-firstboot.service.d/jeos-firstboot-diskencrypt-override.conf"
		cp "${0%/*}/jeos-firstboot-enroll" "$mp/usr/share/jeos-firstboot/modules/enroll"
	fi

	mount -t overlay overlay \
		-o lowerdir="$mp/usr/lib/dracut/modules.d/,upperdir=$tmpdir/overlay,workdir=$tmpdir/overlay-w" \
		"$mp/usr/lib/dracut/modules.d/"

	call_dracut

	exit 0
fi

read -r minsize bytes _rest < <(btrfs inspect-internal min-dev-size "$mp")
isdigits "$minsize" || err "Failed to read minimum btrfs size"
[ "$bytes" = 'bytes' ] || err "Failed to read minimum btrfs size"

log_info "resizing fs"
btrfs filesystem resize "$minsize" "$mp"

if [ -e "$tmpdir/mounts" ]; then
	# subshell intentional here
	tac "$tmpdir/mounts" | while read -r line; do
		eval "$line"
		umount "$TARGET"
	done
else
	umount "$mp"
fi
unset mp

settle_umount_events

# shrink partition to a minimum so reencryption doesn't write everything
log_info "resizing partition"
echo "size=$((minsize/1024+32*1024))KiB" | sfdisk -q -N "$partno" "$blkdev"
udevadm settle

if [ -n "$gen_key" ]; then
	read -r password < <(generate-recovery-key)
	echo -e "Recovery key: \e[1m$password\e[m"
	if [ -e /etc/initrd-release ]; then
		read -r key_id < <(echo -n "$password" | keyctl padd user cryptenroll @u)
	fi
fi

echo "Encrypting..."
encrypt "$@"

log_info "grow partition again"
echo ", +" | sfdisk --no-reread -q -N "$partno" "$blkdev"
if [ -e /etc/initrd-release ]; then
	# seems to be the only way to tell the kernel about a specific partition change
	partx -u --nr "$partno" "$blkdev" || :
	# now resize the mapping. For some reason cryptsetup wants a passphrase. Hack
	# around this by installing a token that makes it read the key we installed
	# before, then remove the token again o_O
	cryptsetup token add --key-slot 0 --key-description cryptenroll --token-id 9 "$blkpart"
	cryptsetup resize "$cr_name" < /dev/null
	cryptsetup token remove --token-id 9 "$blkpart"
fi

if [ -z "$mounted" ]; then
	mount -o rw "$cr_dev" "/mnt"
	mp="/mnt"
else
	read -r line < "$tmpdir/mounts"
	eval "$line"
	mapfile -td, options < <(echo -n "$OPTIONS")
	for ((i=0;i<${#options};++i)); do [ "${options[i]}" = ro ] && options[i]=rw; done
	OPTIONS="$(IFS=, eval echo '"${options[*]}"')"
	[ "$SOURCE" = "$blkpart" ] && SOURCE="$cr_dev"
	mount "$cr_dev" "$TARGET" -t "$FSTYPE" -o "$OPTIONS"
	mp="$TARGET"
fi

log_info "resizing fs to max again"
btrfs filesystem resize max "$mp"

make_rw

declare loop_UUID
eval "$(blkid -c /dev/null -o export "$blkpart"|sed 's/^/loop_/')"
if [ -n "$loop_UUID" ]; then
	echo "$cr_name /dev/disk/by-uuid/$loop_UUID none x-initrd.attach" > "$mp"/etc/crypttab
else
	warn "Can't determine device UUID. Can't generate crypttab"
fi

mountstuff

if grep -q "LOADER_TYPE.*grub2" "$mp"/etc/sysconfig/bootloader; then
	log_info "Update bootloader"

	echo GRUB_ENABLE_CRYPTODISK=y >> "$mp"/etc/default/grub

	sed -i -e 's/^LOADER_TYPE=.*/LOADER_TYPE="grub2"/' "$mp"/etc/sysconfig/bootloader
	chroot "$mp" update-bootloader --reinit
	sed -i -e 's/^LOADER_TYPE=.*/LOADER_TYPE="grub2-efi"/' "$mp"/etc/sysconfig/bootloader
	chroot "$mp" update-bootloader --reinit
	mv "$mp/boot/grub2/grub.cfg" "$mp/boot/grub2/grub.cfg.bak"
	cat > "$mp/boot/grub2/grub.cfg" <<-'EOF'
	set linux=linux
	set initrd=initrd
	if [ "${grub_cpu}" = "x86_64" -o "${grub_cpu}" = "i386" ]; then
	    if [ "${grub_platform}" = "efi" ]; then
		set linux=linuxefi
		set initrd=initrdefi
	    fi
	fi
	export linux initrd
	EOF
	sed -e 's/linuxefi/$linux/;s/initrdefi/$initrd/' < "$mp/boot/grub2/grub.cfg.bak" >> "$mp/boot/grub2/grub.cfg"
	rm "$mp/boot/grub2/grub.cfg.bak"
elif [ -e "$mp/etc/kernel/entry-token" ]; then
	: # sd-boot
else
	log_info "unsupported boot loader"
	grep LOADER_TYPE "$mp"/etc/sysconfig/bootloader
fi

# A new initrd is created as side effect of the enrolment
# (jeos-firtboot module), as this calls sdbootutil

make_ro

echo "Image encryption completed"
07070100000004000081ED0000000000000000000000016686408200000480000000000000000000000000000000000000004700000000disk-encryption-tool-1+git20240704.5a6539c/disk-encryption-tool-dracut#!/bin/sh

exec < /dev/console >/dev/console 2>&1
type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh

# get systemd credential
# https://systemd.io/CREDENTIALS/
get_credential()
{
	local var="${1:?}"
	local name="${2:?}"
	[ -n "$CREDENTIALS_DIRECTORY" ] || return 1
	[ -e "$CREDENTIALS_DIRECTORY/$name" ] || return 1
	read -r "$var" < "$CREDENTIALS_DIRECTORY/$name" || [ -n "${!var}" ]
}

encrypt=
if get_credential encrypt rd.encrypt && [ "$encrypt" = "no" ]; then
	exit 0
fi

# check whether encryption was explicitly turned off
if ! getargbool 1 rd.encrypt; then
	exit 0
fi

# XXX: this is so dirty
systemctl start sysroot.mount
mount --target-prefix /sysroot --fstab /sysroot/etc/fstab /var
if [ ! -e /sysroot/var/lib/YaST2/reconfig_system ]; then
	echo "system already configured, no encryption"
	umount /sysroot/var
	exit 0
fi
umount /sysroot/var

# silence systemd
kill -SIGRTMIN+21 1
echo -ne '\n\n\a'
read -n1 -s -r -t 10 -p "*** Press ESC to prevent encrypting the disk" inhibitor
echo
if [ "$inhibitor" != $'\e' ]; then
	/usr/bin/disk-encryption-tool -v --gen-key || die "Encryption failed"
fi
# turn messages on again
kill -SIGRTMIN+20 1
07070100000005000081A40000000000000000000000016686408200000342000000000000000000000000000000000000004F00000000disk-encryption-tool-1+git20240704.5a6539c/disk-encryption-tool-dracut.service[Unit]
Description=Encrypt root disk
DefaultDependencies=false

# /sysroot needs to be available, but it's temporarily stopped
# for remounting so a direct requirement is not possible
Requires=initrd-root-device.target
After=initrd-root-device.target

After=combustion.service

# After ignition completed its stuff
After=ignition-complete.target

# So that /etc/fstab's x-initrd.mount entries are read (again) later
Before=initrd-parse-etc.service

Conflicts=initrd-switch-root.target umount.target
Conflicts=dracut-emergency.service emergency.service emergency.target

# Without this it goes into an endless loop on failure
OnFailure=emergency.target
OnFailureJobMode=isolate

[Service]
Type=oneshot
KeyringMode=shared
ExecStart=/usr/bin/disk-encryption-tool-dracut
ImportCredential=rd.encrypt

[Install]
RequiredBy=firstboot.target
07070100000006000081A40000000000000000000000016686408200000C16000000000000000000000000000000000000004500000000disk-encryption-tool-1+git20240704.5a6539c/disk-encryption-tool.spec#
# spec file for package disk-encryption-tool
#
# Copyright (c) 2024 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.

# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
# icecream 0

%if 0%{?_build_in_place}
%define git_version %(git log '-n1' '--date=format:%Y%m%d' '--no-show-signature' "--pretty=format:+git%cd.%h")
BuildRequires:  git-core
%else
# this is required for obs' source validator. It's
# 20-files-present-and-referenced ignores all conditionals. So the
# definition of git_version actually happens always.
%define git_version %{nil}
%endif

Name:           disk-encryption-tool
Version:        84.87%{git_version}
Release:        0
Summary:        Tool to reencrypt kiwi raw images
License:        MIT
URL:            https://github.com/lnussel/disk-encryption-tool
Source:         disk-encryption-tool-%{version}.tar
Requires:       cryptsetup
Requires:       keyutils
Requires:       pcr-oracle
# something needs to require it. Can be us.
Requires:       tpm2.0-tools
Requires:       qrencode
ExclusiveArch:  aarch64 ppc64le riscv64 x86_64

%description
Convert a plain text kiwi image into one with LUKS full disk
encryption. Supports both raw and qcow2 images. It assumes that the
third partition is the root fs using btrfs.
After encrypting the disk, the fs is mounted and a new initrd
created as well as the grub2 config adjusted.

%prep
%setup -q

%build

%install
mkdir -p %buildroot/usr/lib/dracut/modules.d/95disk-encryption-tool
for i in disk-encryption-tool{,-dracut,-dracut.service}  module-setup.sh generate-recovery-key; do
  cp "$i" %buildroot/usr/lib/dracut/modules.d/95disk-encryption-tool/"$i"
done
mkdir -p %buildroot/usr/bin
ln -s ../lib/dracut/modules.d/95disk-encryption-tool/disk-encryption-tool %buildroot/usr/bin
ln -s ../lib/dracut/modules.d/95disk-encryption-tool/generate-recovery-key %buildroot/usr/bin
install -D -m 644 jeos-firstboot-diskencrypt-override.conf \
	%{buildroot}/usr/lib/systemd/system/jeos-firstboot.service.d/jeos-firstboot-diskencrypt-override.conf
install -D -m 644 jeos-firstboot-enroll %buildroot/usr/share/jeos-firstboot/modules/enroll

%files
%license LICENSE
/usr/bin/disk-encryption-tool
/usr/bin/generate-recovery-key
%dir /usr/lib/dracut
%dir /usr/lib/dracut/modules.d
/usr/lib/dracut/modules.d/95disk-encryption-tool
%dir /usr/share/jeos-firstboot
%dir /usr/share/jeos-firstboot/modules
/usr/share/jeos-firstboot/modules/enroll
%dir /usr/lib/systemd/system/jeos-firstboot.service.d
/usr/lib/systemd/system/jeos-firstboot.service.d/jeos-firstboot-diskencrypt-override.conf

%changelog

07070100000007000081ED00000000000000000000000166864082000001C9000000000000000000000000000000000000004100000000disk-encryption-tool-1+git20240704.5a6539c/generate-recovery-key#!/bin/bash
set -e
modhex=('c' 'b' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'n' 'r' 't' 'u' 'v')
mapfile -t raw_key < <(hexdump -v --format '1/1 "%u\n"' -n 32 /dev/random)
[ "${#raw_key[@]}" = 32 ]
key=""
for ((i=0;i<"${#raw_key[@]}";++i)); do
	[ "$i" -gt 0 ] && [ "$((i%4))" -eq 0 ] && key="$key-"
	c="${raw_key[i]}"
	key="$key${modhex[$((c>>4))]}${modhex[$((c&15))]}"
done
[ -x /usr/bin/qrencode ] && [ -t 1 ] && echo -n "$key" | qrencode -t utf8i
echo "$key"
07070100000008000081A4000000000000000000000001668640820000001D000000000000000000000000000000000000005400000000disk-encryption-tool-1+git20240704.5a6539c/jeos-firstboot-diskencrypt-override.conf[Service]
KeyringMode=shared
07070100000009000081A4000000000000000000000001668640820000222F000000000000000000000000000000000000004100000000disk-encryption-tool-1+git20240704.5a6539c/jeos-firstboot-enroll#!/bin/bash

crypt_keyid=""
crypt_pw=""
crypt_tpm_pin=""
# for pin
cryptenroll_tpm_extra_args=()

with_fido2=
with_tpm2=

luks2_devices=()

# After the enrolling, other tools can find this list in
# /etc/sysconfig/fde-tools
if [ $(sdbootutil bootloader) = "systemd-boot" ]; then
	FDE_SEAL_PCR_LIST="0,2,4,7,9"
elif [ $(sdbootutil bootloader) = "grub2" ]; then
	FDE_SEAL_PCR_LIST="0,2,4,7,8,9"
else
	d --msgbox "Error: Bootloader not detected" 0 0
fi


have_luks2()
{
	[ "${#luks2_devices[@]}" -gt 0 ]
}

detect_luks2()
{
	local dev fstype
	[ -z "$luks2_devices" ] || return 0
	while read -r dev fstype; do
		[ "$fstype" = 'crypto_LUKS' ] || continue
		cryptsetup isLuks --type luks2 "$dev" || continue
		luks2_devices+=("$dev")
	done < <(lsblk --noheadings -o PATH,FSTYPE)
	have_luks2
}

# exit early without defining any helper functions if there are no luks devices
detect_luks2 || return 0

enroll_systemd_firstboot() {
	[ -e /usr/bin/systemd-cryptenroll ] || return 0
	crypt_keyid="$(keyctl id %user:cryptenroll 2> /dev/null)" || return 0
	[ -n "$crypt_keyid" ] || return 0

	welcome_screen_with_console_switch

	local has_fido2=${JEOS_HAS_FIDO2:-}
	local has_tpm2=

	[ -z "$(systemd-cryptenroll --fido2-device=list 2>/dev/null)" ] || has_fido2=1
	if [ -e '/sys/class/tpm/tpm0' ]; then
		if have_pcrlock && ! is_pcr_oracle; then
			has_tpm2=lock
		elif have_pcr_oracle; then
			has_tpm2=oracle
		fi
	fi

	while true; do
		local list=()

		if [ -z "$with_fido2" ] && [ -z "$with_tpm2" ] && [ -n "$has_fido2" ]; then
			list+=('FIDO2' $'Enroll FIDO2 token')
		fi
		if [ -z "$with_tpm2" ] && [ -z "$with_fido2" ] && [ -n "$has_tpm2" ]; then
			list+=('TPM2' $'Enroll TPM2 based token' 'TPM2_interactive' 'Enroll TPM2 based token with PIN')
		fi
		if [ -z "$crypt_pw" ]; then
			if [ -n "$password" ]; then
				list+=('root' $'Enroll root password')
			fi
			list+=('password' $'Enroll extra password')
		fi
		[ -n "$list" ] || break

		list+=('done' $'Done')

		d --no-tags --default-item "${list[0]}" --menu $"Disk Encryption" 0 0 "$(menuheight ${#list[@]})" "${list[@]}"
		if [ "$result" = 'done' ]; then
			if [ -z "$crypt_pw" ] && [ -z "$with_fido2" ] && [ -z "$with_tpm2" ] && [ -z "$is_jeos_config" ]; then
				d_styled --yesno $"Neither password, TPM2 nor FIDO2 entrolled. Unlocking disk will only work with recovery key. Is this intended?" 0 0 || continue
			fi
			break;
		elif [ "$result" = 'FIDO2' ]; then
			with_fido2=1
		elif [ "$result" = 'TPM2' ]; then
			with_tpm2="$has_tpm2"
		elif [ "$result" = 'TPM2_interactive' ]; then
			while true; do
				d --insecure --passwordbox  $"Enter new PIN (actually just passphrase)" 0 0
				if [ -z "$result" ]; then
					d_styled --yesno $"Retry?" 0 0 || break
					continue
				fi
				crypt_tpm_pin="$result"
				d --insecure --passwordbox  $"Confirm PIN" 0 0
				[ "$crypt_tpm_pin" != "$result" ] || { with_tpm2="$has_tpm2"; break; }
				d --msgbox $"PINs don't match. Try again" 0 0
			done

		elif [ "$result" = 'root' ]; then
			crypt_pw="$password"
		elif [ "$result" = 'password' ]; then
			while true; do
				d --insecure --passwordbox  $"Enter encryption password" 0 0
				if [ -z "$result" ]; then
					d --aspect 29 --msgbox $"No encryption password set. You can add more keys manually using systemd-cryptenroll." 0 0
					break
				fi
				crypt_pw="$result"
				d --insecure --passwordbox  $"Confirm encryption password" 0 0
				[ "$crypt_pw" != "$result" ] || break
				d --msgbox $"Passwords don't match. Try again" 0 0
			done
		else
			d --msgbox "Error: $result" 0 0
		fi
	done

	return 0
}

enroll_fido2() {
	local dev="$1"

	echo "Enrolling with FIDO2: $dev"

	# The password is read from "cryptenroll" kernel keyring
	run systemd-cryptenroll --fido2-device=auto "$dev"
}

generate_rsa_key() {
	[ -z "$dry" ] && mkdir -p /etc/systemd
	run pcr-oracle \
		--rsa-generate-key \
		--private-key /etc/systemd/tpm2-pcr-private-key.pem \
		--public-key /etc/systemd/tpm2-pcr-public-key.pem \
		store-public-key
}

enroll_tpm2_pcr_oracle() {
	local dev="$1"

	echo "Enrolling with TPM2 (pcr-oracle): $dev"

	# The password is read from "cryptenroll" kernel keyring
	# XXX: Wipe is separated by now (possible systemd bug)
	run systemd-cryptenroll \
		--wipe-slot=tpm2 \
		"$dev"

	NEWPIN="$crypt_tpm_pin" run systemd-cryptenroll \
		--tpm2-device=auto \
		"${cryptenroll_tpm_extra_args[@]}" \
		--tpm2-public-key=/etc/systemd/tpm2-pcr-public-key.pem \
		--tpm2-public-key-pcrs="$FDE_SEAL_PCR_LIST" \
		"$dev"
}

enroll_tpm2_pcrlock() {
	local dev="$1"

	echo "Enrolling with TPM2 (pcrlock): $dev"

	# The password is read from "cryptenroll" kernel keyring
	# XXX: Wipe is separated by now (possible systemd bug)
	run systemd-cryptenroll \
		--wipe-slot=tpm2 \
		"$dev"

	# Note that the PCRs are now not stored in the LUKS2 header
	NEWPIN="$crypt_tpm_pin" run systemd-cryptenroll \
		--tpm2-device=auto \
		"${cryptenroll_tpm_extra_args[@]}" \
		--tpm2-pcrlock=/var/lib/systemd/pcrlock.json \
		"$dev"
}

update_crypttab_options() {
	# This version will share the same options for all crypto_LUKS
	# devices.  This imply that all of them will be unlocked by the
	# same TPM2, or the same FIDO2 key
	local options="$1"

	# TODO: this needs to be unified with disk-encryption-tool
	local crypttab
	if [ -z "$dry" ]; then
		crypttab="$(mktemp -t disk-encryption-tool.crypttab.XXXXXX)"
	else
		crypttab=/dev/stdout
	fi
	echo "# File created by jeos-firstboot-enroll.  Comments will be removed" > "$crypttab"

	local name
	local device
	local key
	local opts
	while read -r name device key opts; do
		[[ "$name" = \#* ]] && continue
		echo "$name $device $key $options" >> "$crypttab"
	done < /etc/crypttab

	run mv "$crypttab" /etc/crypttab
	run chmod 644 /etc/crypttab
}

have_pcrlock() {
	[ -e /usr/lib/systemd/systemd-pcrlock ]
}

have_pcr_oracle() {
	[ -e /usr/bin/pcr-oracle ]
}

is_pcr_oracle() {
	have_pcr_oracle && \
		[ -e /etc/systemd/tpm2-pcr-public-key.pem ] && \
		[ -e /etc/systemd/tpm2-pcr-private-key.pem ]
}

write_issue_file() {
	if [ -e '/usr/sbin/issue-generator' ] && [ -z "$dry" ]; then
		mkdir -p "/run/issue.d/"
		issuefile="/run/issue.d/90-diskencrypt.conf"
	else
		issuefile='/dev/stdout'
	fi

	echo -ne "Encryption recovery key:\n  " > "$issuefile"
	keyctl pipe "$crypt_keyid" >> "$issuefile"
	echo -e "\n" >> "$issuefile"
	if [ -x /usr/bin/qrencode ]; then
		echo "You can also scan it with your mobile phone:" >> "$issuefile"
		keyctl pipe "$crypt_keyid" | qrencode -t utf8i >> "$issuefile"
	fi

	run issue-generator
	[ -n "$dry" ] || cat "$issuefile"
}

add_password() {
	[ -n "$crypt_pw" ] || return 0
	local dev
	for dev in "${luks2_devices[@]}"; do
		echo "adding password to $dev"
		echo -n "$crypt_pw" | run cryptsetup luksAddKey --verbose --batch-mode --force-password --key-file <(keyctl pipe "$crypt_keyid") "$dev"
	done
}

enroll_post() {
	[ -e /usr/bin/systemd-cryptenroll ] || return 0
	[ -n "$crypt_keyid" ] || return 0

	write_issue_file

	add_password

	enroll_tpm_and_fido
}

enroll_tpm_and_fido() {
	# For now is a first step before moving into fde-tools
	local fde_cfg='/etc/sysconfig/fde-tools'
	if [ -e "$fde_cfg" ]; then
		. "$fde_cfg"
	else
		[ -z "$dry" ] || fde_cfg=/dev/stdout
		echo "FDE_SEAL_PCR_LIST=${FDE_SEAL_PCR_LIST}" > "$fde_cfg"
	fi

	local dev
	local fstype

	local crypttab_options="x-initrd.attach"

	# Generate first the crypttab + initrd, so the predictions can be
	# done in case of pcrlock
	if [ "$with_fido2" = '1' ]; then
		crypttab_options+=",fido2-device=auto"
	elif [ -n "$with_tpm2" ]; then
		crypttab_options+=",tpm2-device=auto"
	fi
	update_crypttab_options "$crypttab_options"

	if [ "$with_tpm2" = 'oracle' ]; then
		generate_rsa_key
	else
		# sdbootutil will generate predictions for pcrlock
		SDB_ADD_INITIAL_COMPONENT=1 run sdbootutil add-all-kernels --no-reuse-initrd
	fi

	if [ "$with_fido2" = '1' ]; then
		for dev in "${luks2_devices[@]}"; do
			enroll_fido2 "$dev"
		done
	elif [ -n "$with_tpm2" ]; then
		if [ -n "$crypt_tpm_pin" ]; then
			# XXX ./src/cryptenroll/cryptenroll-tpm2.c lacks accept cached
			#echo -n "$crypt_tpm_pin" | run keyctl padd user tpm2-pin @u
			cryptenroll_tpm_extra_args+=(--tpm2-with-pin=1)
		fi
		for dev in "${luks2_devices[@]}"; do
			if [ "$with_tpm2" = 'lock' ]; then
				enroll_tpm2_pcrlock "$dev"
			else
				enroll_tpm2_pcr_oracle "$dev"
			fi
		done
	fi

	if [ "$with_tpm2" = 'oracle' ]; then
		# with pcr-oracle we pick up settings from the luks header
		run sdbootutil add-all-kernels --no-reuse-initrd
	fi
}

enroll_jeos_config() {
	is_jeos_config=1
	d --insecure --passwordbox  $"Enter decryption password" 0 0
	[ -n "$result" ] || return 0
	echo -n "$result" | keyctl padd user cryptenroll @u

	enroll_systemd_firstboot

	add_password

	enroll_tpm_and_fido
}
0707010000000A000081ED00000000000000000000000166864082000003F5000000000000000000000000000000000000003B00000000disk-encryption-tool-1+git20240704.5a6539c/module-setup.sh#!/bin/bash

# called by dracut
check() {
	require_any_binary cryptsetup || return 1
	return 0
}

# called by dracut
depends() {
	echo "crypt"
	return 0
}

# called by dracut
install() {
	instmods dmi_sysfs # for systemd credentials via smbios
	inst_multiple -o cryptsetup-reencrypt
	inst_multiple cryptsetup btrfs mktemp getopt mountpoint findmnt sfdisk tac sed hexdump keyctl partx

	inst_script "$moddir"/disk-encryption-tool /usr/bin/disk-encryption-tool
	inst_script "$moddir"/disk-encryption-tool-dracut /usr/bin/disk-encryption-tool-dracut
	inst_script "$moddir"/generate-recovery-key /usr/bin/generate-recovery-key

	for service in "disk-encryption-tool-dracut.service"; do
		inst_simple "${moddir}/$service" "${systemdsystemunitdir}/$service"
		$SYSTEMCTL -q --root "$initdir" enable "$service"
		#$SYSTEMCTL -q --root "$initdir" enable "debug-shell.service"
	done

	: "${ENCRYPTION_CONFIG:=/etc/encrypt_options}"
	[ -e "$ENCRYPTION_CONFIG" ] && inst_simple "$ENCRYPTION_CONFIG" "/etc/encrypt_options"
}
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!65 blocks
openSUSE Build Service is sponsored by