#
#   Copyright (C) 2022, 2023 SUSE LLC
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#   Written by Olaf Kirch <okir@suse.com>

alias cmd_requires_luks_device=true
alias cmd_perform=cmd_add_secondary_key

function cmd_add_secondary_key {

    local luks_devices="$1"

    if [ -n "$FDE_ENROLL_NEW_KEY" ]; then
	display_errorbox "It seems you've already tried to enroll a secondary key."
	return 1
    fi

    for luks_dev in ${luks_devices}; do
	keyslots=$(bootloader_get_keyslots ${luks_dev})

	if [ -n "${keyslots}" ]; then
	    display_errorbox "It seems you've already enrolled a secondary key.(${luks_dev})"
	    return 1
	fi
    done

    if ! enroll_tpm_secondary_key "${luks_devices}"; then
	return 1
    fi

    return 0
}

function init_authorized_policy {

    policy_name="$FDE_AUTHORIZED_POLICY"
    if [ -z "$policy_name" ]; then
	policy_name="$FDE_DEFAULT_AUTHORIZED_POLICY"
    fi

    ##################################################################
    # Create the policy. If the private key does not exist yet,
    # pcr-oracle will generate a suitable key.
    # We also store a copy of the public key in a TPMv2 format so that
    # boot loaders do need a full PEM/ASN.1/bignum library just for
    # loading the pubkey.
    tpm_set_authorized_policy_paths "$policy_name"
    tpm_create_authorized_policy $FDE_AP_SECRET_KEY $FDE_AP_AUTHPOLICY $FDE_AP_PUBLIC_KEY
    if [ $? -ne 0 ]; then
	display_errorbox "Failed to create authorized policy"
	return 1
    fi

    if [ "$FDE_AUTHORIZED_POLICY" != "$policy_name" ]; then
	fde_set_variable FDE_AUTHORIZED_POLICY "$policy_name"
    fi

    test -n "$FDE_AUTHORIZED_POLICY" || fde_bad_argument "FDE_AUTHORIZED_POLICY not set"
}

function add_secondary_key {

    local luks_devices="$1"
    local luks_new_keyfile="$2"

    luks_keyfile=$(fde_make_tempfile pass.key)
    if ! fde_request_recovery_passfile "$luks_keyfile"; then
	display_errorbox "Unable to obtain recovery password; aborting."
	return 1
    fi

    # Verify the recovery password on all specified LUKS partitions first
    for luks_dev in ${luks_devices}; do
	if ! luks_verify_password "$luks_dev" "$luks_keyfile"; then
	    rm -f "$luks_keyfile"
	    display_errorbox "Failed to verify password on LUKS partition (${luks_dev})"
	    return 1
	fi
    done

    luks_generate_random_key ${luks_new_keyfile}

    # Add the new random key to all specified LUKS partitions
    for luks_dev in ${luks_devices}; do
	if ! luks_add_key "${luks_dev}" "${luks_keyfile}" "${luks_new_keyfile}"; then
	    display_errorbox "Failed to add secondary LUKS key (${luks_dev})"
	    rm -f "$luks_keyfile"
	    return 1
	fi
    done

    rm -f "$luks_keyfile"
}

function enroll_tpm_secondary_key {

    local luks_devices="$1"

    if [[ "$FDE_USE_AUTHORIZED_POLICIES" =~ y.* ]]; then
	luks_new_keyfile="$(fde_make_tempfile newkey)"
	if ! init_authorized_policy || ! add_secondary_key "${luks_devices}" "${luks_new_keyfile}"; then
	    rm -f "$luks_new_keyfile"
	    return 1
	fi

	if ! tpm_seal_secret "$luks_new_keyfile" "$FDE_AP_SEALED_SECRET" "$FDE_AP_AUTHPOLICY"; then
	    display_errorbox "Failed to seal secondary LUKS key against TPM Authorized Policy"
	    rm -f "$luks_new_keyfile"
	    return 1
	fi

	rm -f "$luks_new_keyfile"
    else
	if [ -z "$opt_keyfile" ]; then
	    opt_keyfile="/etc/fde/root.key"
	fi

	if ! add_secondary_key "$luks_devices" "$opt_keyfile"; then
	    return 1
	fi

	# Leave the keyfile around so that tpm-enable can seal it on the next reboot
	echo "Leaving secondary key in $opt_keyfile"
	fde_set_variable FDE_ENROLL_NEW_KEY "$opt_keyfile"
    fi
}
