#!/bin/bash

SCRIPT_NAME=${0}
SCRIPT_DIR=$(dirname $(readlink -f ${0}) )
FIVE_EVMCTL=$(readlink -m "${SCRIPT_DIR}/five_evmctl")
PA_SIGNER=$(readlink -m "${SCRIPT_DIR}/../out/host/pa_signer/pa_signer")
IMA_KEY="${SCRIPT_DIR}/../config/five/privkey_five.pem"
PA_KEY="${SCRIPT_DIR}/../config/pa/root_eng_private.key"
PUSH_DESTINATION="/system/bin"
PA_ENABLED=1
PA_USER_KEY=
SIGN_SO=0
ADB_FLAGS=""
FIVE_EVMCTL_FLAGS=""

set -e

function usage()
{

cat <<EOF
Usage: ${SCRIPT_NAME} [OPTIONS]... FILES...
Push FIVE-signed file to device

  -h, --help                   display this help and exit
  -k, --ima-key <KEYFILE>      IMA private key for FIVE
  -p, --pkg-name <PACKAGE NAME> APK package name
  -d, --destination            Destination on device
  -s <SERIAL>                  Device serial number for connection to specified device
      --five-only              Do only FIVE provisioning
      --sign-so                Enable PA provisioning for shared libraries
      --sign                   Ability to sign files

Examples:
  ${SCRIPT_NAME} tbase_pa_daemon -d /system/bin 
  ${SCRIPT_NAME} libtbase_platform_client.so -d /system/lib64 
  ${SCRIPT_NAME} SecureStorageClient.apk -p com.sec.android.secureclient -d /system/priv-app/SecureStorageClient

EOF
}


function gen_sig()
{
	local FILE_DIR=$(dirname ${1}) 
    local FILENAME=$(basename ${1})
    local MOUNTPOINT=$(readlink -m ${2})
    local OUT_FILE=$(readlink -m ${3})
    local CWD=`pwd`

	cd ${FILE_DIR}
	${FIVE_EVMCTL} -f ima_sign -s -k ${IMA_KEY} ${FILENAME} --five --five-mountpoint=${MOUNTPOINT} ${FIVE_EVMCTL_FLAGS} >> ${OUT_FILE}
	cd ${CWD}
}

# generate signatures from given FIVE signatures in file $IN_FILE to PA signatures in $OUT_FILE
# file format for each line of both input and output files: <path to file> <security.five> <base64 encoded signature>
function gen_pa_sigs() # ($IN_FILE, $OUT_FILE)
{
    local IN_FILE=$(readlink -m ${1})
    local OUT_FILE=$(readlink -m ${2})
    local LINE ITEMS FIVE_PATH FIVE_SIG
    cat ${IN_FILE} | while read LINE; do
        ITEMS=($LINE)
        FIVE_PATH=${ITEMS[0]}
        FIVE_SIG=${ITEMS[2]} # signature is arranged on 3rd position
        if (( ! $SIGN_SO )) && grep -q "\.so$" <<< ${FIVE_PATH}; then
            echo "PA: skip shared object: ${FIVE_PATH}"
        else
            echo "PA: prepare signature: ${FIVE_PATH}..."
            ${PA_SIGNER} --cmd sign --path ${FIVE_PATH} --five-sig ${FIVE_SIG} ${PA_USER_KEY} --key ${PA_KEY} >> ${OUT_FILE}
        fi
    done;
}

# generate signatures from given FIVE signatures in file $IN_FILE to PA signatures in $OUT_FILE
# for Android application $APK with package name $PACKAGE
# file format for each line of both input and output files: <path to file> <base64 encoded signature>
function gen_pa_android_sigs() # ($IN_FILE, $OUT_FILE, $PACKAGE, $APK)
{
    local IN_FILE=$(readlink -m ${1})
    local OUT_FILE=$(readlink -m ${2})
    local PACKAGE=${3}
    local APK=$(readlink -m ${4})
    local TMP_DIR="rsa_temp"
    local LINE ITEMS FIVE_PATH FIVE_SIG UNZIP
    cat ${IN_FILE} | while read LINE; do
        ITEMS=($LINE)
        FIVE_PATH=${ITEMS[0]}
        FIVE_SIG=${ITEMS[2]}
        UNZIP=`unzip ${APK} META-INF/CERT.RSA -d ${TMP_DIR}`
        echo "PA: prepare signature: ${FIVE_PATH}..."
        ${PA_SIGNER} --cmd sign --path ${FIVE_PATH} --pkg-name ${PACKAGE} --pkg-key ${TMP_DIR}/META-INF/CERT.RSA --five-sig ${FIVE_SIG} ${PA_USER_KEY} --key ${PA_KEY} >> ${OUT_FILE}
    done;
    rm -rf ${TMP_DIR}
}

ARGS=`getopt -o huk:p:d:s: --long help,user,ima-key:,pkg-name:,destination:,five-only,sign-so,sign -n "${SCRIPT_NAME}" -- "$@"`
eval set -- "$ARGS"

# extract options and their arguments into variables.
while true ; do
	case "$1" in
		-h|--help)
			usage;
			exit 0;
			shift ;;
		-u|--user) PA_USER_KEY=--user ; shift ;;
		-k|--ima-key) IMA_KEY=${2} ; shift 2;; 
		-p|--pkg-name) PACKAGE=${2} ; shift 2;;
        -d|--destination) PUSH_DESTINATION=${2} ; shift 2;; 
        -s) ADB_FLAGS+=" -s ${2}" ; shift 2;;
        --five-only) PA_ENABLED=0; shift;;
        --sign-so) SIGN_SO=1; shift;;
        --sign) FIVE_EVMCTL_FLAGS="--privilege 1 "; shift;;
        --) shift ; break ;;
        *) echo "${SCRIPT_NAME}: getopt error" ; exit 1 ;;
    esac
done

# remove previously created files
test -f ima_tmp_sigs.txt && rm ima_tmp_sigs.txt
test -f pa_tmp_sigs.txt && rm pa_tmp_sigs.txt

for INPUT_FILE in $@; do
	echo "FIVE: prepare file: ${INPUT_FILE}"
    gen_sig $INPUT_FILE $PUSH_DESTINATION ima_tmp_sigs.txt 
    adb ${ADB_FLAGS} push $INPUT_FILE $PUSH_DESTINATION/$(basename $INPUT_FILE)
done

if [ -f ima_tmp_sigs.txt ]; then
	echo "FIVE: push necessary files to device..."
	DEVICE_APP_ABI=`adb ${ADB_FLAGS} shell getprop ro.product.cpu.abi`
	FIVE_PROVISIONER=$(readlink -m "${SCRIPT_DIR}/xattr/${DEVICE_APP_ABI}/xattr_manager")
	adb ${ADB_FLAGS} push ${FIVE_PROVISIONER} /system/bin
	adb ${ADB_FLAGS} push ima_tmp_sigs.txt /data/local/tmp
	echo "FIVE: run provisioning on device..."
	adb ${ADB_FLAGS} shell xattr_manager --import /data/local/tmp/ima_tmp_sigs.txt
	adb ${ADB_FLAGS} shell rm /data/local/tmp/ima_tmp_sigs.txt
	echo "FIVE: provisioning done"
else
	echo "FIVE: no files for provisioning"
	exit 1
fi

if [ $PA_ENABLED -eq 1 ]; then
    if [ -n "${PACKAGE}" ]; then
        echo "PA: prepare signatures for Android application"
        gen_pa_android_sigs ima_tmp_sigs.txt pa_tmp_sigs.txt ${PACKAGE} $@
    else
        echo "PA: prepare signatures for native application"
        gen_pa_sigs ima_tmp_sigs.txt pa_tmp_sigs.txt
    fi

	if [ -f pa_tmp_sigs.txt ]; then
		echo "PA: push necessary files to device..."
		adb ${ADB_FLAGS} push pa_tmp_sigs.txt /data/local/tmp
		echo "PA: run provisioning on device..."
		adb ${ADB_FLAGS} shell xattr_manager --import /data/local/tmp/pa_tmp_sigs.txt --name user.pa
		adb ${ADB_FLAGS} shell rm /data/local/tmp/pa_tmp_sigs.txt
		rm pa_tmp_sigs.txt
		echo "PA: provisioning done"
	else
		echo "PA: no files for provisioning"
	fi
else
	echo "PA: provisioning disabled"
fi

rm ima_tmp_sigs.txt
