#!/bin/bash
function gen_vehicle_csr {
    SEALED_KEY_FILENAME="$VEHICLE_NAME.bin"
    UNSEALED_KEY_FILENAME="$VEHICLE_NAME.key"
    CSR_SUBJECT="/C=$VEHICLE_CSR_COUNTRY/ST=$VEHICLE_CSR_STATE/L=$VEHICLE_CSR_LOCALITY/O=$VEHICLE_CSR_ORG/OU=$VEHICLE_CSR_ORG_UNIT/CN=$VEHICLE_NAME"
    SANITIZED_CSR_CONTENT=

    if [ "$IS_LOCAL" = "true" ]; then
        # provisioning locally
        # ensure birth cert generation directory exists. If not, create it.

        if ! "$VEHICLE_MKDIR" -p "$BIRTH_GEN_DIR"; then
            echo "Could not create the birth cert generation directory: $BIRTH_GEN_DIR . Check permissions."
            exit 1
        fi
        # clear the contents of the birth cert generation directory, to ensure we do not re-use any csr/key created previously
        if ! "$VEHICLE_RM" -f "$BIRTH_GEN_DIR/$BIRTH_GEN_EXTENSIONS"; then
            echo "Could not clear existing contents of the birth cert generation directory: $BIRTH_GEN_DIR . Check permissions."
            exit 1
        fi
        # generate key pair and csr (particular command depends on existence of tpm)
        if [ "$VEHICLE_TPM" = "true" ]; then
            # generating keypair, private key is sealed using the tpm
            if ! OPENSSL_ENGINES="$TPM2TSS_ENGINE" TPM2TSSENGINE_TCTI="$VEHICLE_TPM2TSSENGINE_TCTI" "$TPM2TSS_GENKEY" -a "$VEHICLE_BIRTH_KEY_ALG" -s "$VEHICLE_BIRTH_KEY_SIZE" "$BIRTH_GEN_DIR/$SEALED_KEY_FILENAME"; then
                echo "Could not generate key pair using TPM. Ensure TPM software stack are installed correctly."
                exit 1
            fi
            # generating csr
            if ! "$VEHICLE_OPENSSL" req -engine tpm2tss -keyform ENGINE -new -key "$BIRTH_GEN_DIR"/"$SEALED_KEY_FILENAME" -out "$BIRTH_GEN_DIR"/"$VEHICLE_NAME".csr  -subj "$CSR_SUBJECT"; then
                echo "Could not generate CSR using TPM. Ensure TPM software stack are installed correctly."
                exit 1
            fi
        else
            if [ "$VEHICLE_TPM" = "false" ]; then
            # generating csr without a tpm. Private key will be unsealed. Primary use is for vehicles that do not yet have the TPM chip.
            # generating unsealed private key
            if ! "$VEHICLE_OPENSSL" genpkey -algorithm "$VEHICLE_BIRTH_KEY_ALG" -out "$BIRTH_GEN_DIR"/"$UNSEALED_KEY_FILENAME" -pkeyopt "$VEHICLE_BIRTH_KEY_NOTPM_OPTIONS"; then
                echo "Could not generate key (no TPM). Ensure OpenSSL is installed correctly."
                exit 1
            fi
            # generating csr
            if ! "$VEHICLE_OPENSSL" req -new -key "$BIRTH_GEN_DIR"/"$UNSEALED_KEY_FILENAME" -out "$BIRTH_GEN_DIR"/"$VEHICLE_NAME".csr -subj "$CSR_SUBJECT"; then
                echo "Could not generate CSR (no TPM). Ensure OpenSSL is installed correctly."
                exit 1
            fi
            else
                echo "Invalid value for option '-p' or '--with-vehicle-tpm'. Legitimate values are: 'true' or 'false'; case-sensitive and without single-quotes."
            fi
        fi
        # prepare contents of a json file with cert req parameters expected by Vault
        # reading csr and santizing its content (convert csr newlines created by openssl to '\n')
        if ! SANITIZED_CSR_CONTENT=$("$VEHICLE_CAT" "$BIRTH_GEN_DIR/$VEHICLE_NAME".csr | "$VEHICLE_JQ" --raw-input --slurp --compact-output '.'); then
            echo "Could not read and sanitize the local CSR file. Make sure 'jq' and 'cat' are installed and used correctly on target and CSR file is accessible."
            exit 1
        fi

        # adding json file parameters. Vault doesn't seem to return the correct "DER", so we'll use PEM here. We convert it to DER later as it's more compressed, and allows for efficient storage in the tpm chip.
        # Note: Sanitized CSR content is already surrounded with double qutoes, so we don't include them here
        if ! echo "{" \"csr\": "$SANITIZED_CSR_CONTENT" "," \"format\": \"pem\" "}" > "$BIRTH_GEN_DIR"/"$VEHICLE_NAME".json ; then
            echo "Could not generate JSON file."
            exit 1
        fi

    else
        if [ "$IS_LOCAL" = "false" ]; then
            # provisioning remotely
            if [ -z "$VEHICLE_USER" ]; then
                echo "No vehicle user provided for a non-local run."
                exit 1
            fi
            if [ -z "$VEHICLE_ADDR" ]; then
                echo "No vehicle address provided for a non-local run."
                exit 1
            fi

            # ensure birth cert generation directory exists. If not, create it.
            if ! "$OP_SSH" -q "$VEHICLE_USER@$VEHICLE_ADDR" "$VEHICLE_MKDIR -p $BIRTH_GEN_DIR"; then
                echo "Could not create the birth cert generation directory on $VEHICLE_USER@$VEHICLE_ADDR:$BIRTH_GEN_DIR . Check permissions."
                exit 1
            fi
            # clear the contents of the birth cert generation directory, to ensure we do not re-use any csr/key created previously
            if ! "$OP_SSH" -q "$VEHICLE_USER@$VEHICLE_ADDR" "$VEHICLE_RM -f $BIRTH_GEN_DIR/$BIRTH_GEN_EXTENSIONS"; then
                echo "Could not clear existing contents of the birth cert generation directory: $VEHICLE_USER@$VEHICLE_ADDR:$BIRTH_GEN_DIR . Check permissions."
                exit 1
            fi

            # generate key pair and csr (particular command depends on existence of tpm)
            if [ "$VEHICLE_TPM" = "true" ]; then
                # generating keypair, private key is sealed using the tpm
                if ! "$OP_SSH" -q "$VEHICLE_USER@$VEHICLE_ADDR" "OPENSSL_ENGINES=$TPM2TSS_ENGINE TPM2TSSENGINE_TCTI=$VEHICLE_TPM2TSSENGINE_TCTI $TPM2TSS_GENKEY -a $VEHICLE_BIRTH_KEY_ALG -s $VEHICLE_BIRTH_KEY_SIZE $BIRTH_GEN_DIR/$SEALED_KEY_FILENAME"; then
                    echo "Could not generate key pair using TPM. Ensure the vehicle is accessible and TPM software stack are installed correctly on it."
                    exit 1
                fi
                # generating csr
                if ! "$OP_SSH" -q "$VEHICLE_USER@$VEHICLE_ADDR" "$VEHICLE_OPENSSL req -engine tpm2tss -keyform ENGINE -new -key $BIRTH_GEN_DIR/$SEALED_KEY_FILENAME -out $BIRTH_GEN_DIR/$VEHICLE_NAME.csr  -subj $CSR_SUBJECT"; then
                    echo "Could not generate CSR using TPM. Ensure TPM software stack and the corresponding OpenSSL engine is installed correctly."
                    exit 1
                fi
            else
                if [ "$VEHICLE_TPM" = "false" ]; then
                # generating csr without a tpm. Private key will be unsealed. Primary use is for vehicles that do not (yet) have the TPM chip.
                # generating unsealed private key
                if ! "$OP_SSH" -q "$VEHICLE_USER@$VEHICLE_ADDR" "$VEHICLE_OPENSSL genpkey -algorithm $VEHICLE_BIRTH_KEY_ALG -out $BIRTH_GEN_DIR/$UNSEALED_KEY_FILENAME -pkeyopt $VEHICLE_BIRTH_KEY_NOTPM_OPTIONS"; then
                    echo "Could not generate key (no TPM). Ensure the vehicle is accessible and OpenSSL is installed correctly."
                    exit 1
                fi
                # generating csr
                if ! "$OP_SSH" -q "$VEHICLE_USER@$VEHICLE_ADDR" "$VEHICLE_OPENSSL req -new -key $BIRTH_GEN_DIR/$UNSEALED_KEY_FILENAME -out $BIRTH_GEN_DIR/$VEHICLE_NAME.csr -subj $CSR_SUBJECT"; then
                    echo "Could not generate CSR (no TPM) on $VEHICLE_USER@$VEHICLE_ADDR:$BIRTH_GEN_DIR. Ensure the vehicle is accessible and OpenSSL is installed correctly."
                    exit 1
                fi
                else
                    echo "Invalid value for option '-s' or '--with-vehicle-tpm'. Legitimate values are: 'true' or 'false'; case-sensitive and without single-quotes."
                fi
            fi

            # prepare json file with proper cert req parameters expected by Vault
            # reading and santizing csr (replacing newlines added by openssl to the original csr with '\n' using VEHICLE_JQ)
            if ! SANITIZED_CSR_CONTENT=$("$OP_SSH" -q "$VEHICLE_USER@$VEHICLE_ADDR" "$VEHICLE_CAT $BIRTH_GEN_DIR/$VEHICLE_NAME.csr | $VEHICLE_JQ --raw-input --slurp --compact-output '.' " ); then
                echo "Could not read and sanitize the remote CSR file. Make sure 'jq' AND 'cat' are installed and used correctly on target and the CSR file is accessible."
                exit 1
            fi
            # adding json file parameters. Vault doesn't seem to return the correct "DER", so we'll use PEM here. We convert it to DER later as it's more compressed, and allows for efficient storage in the tpm chip.
            # Note: Sanitized CSR content is already surrounded with double qutoes, so we don't include them here
            JSON_CONTENT=("{"\"csr\": "$SANITIZED_CSR_CONTENT" "," \"format\": \"pem\" "}")

            # writing json file in vehicle birth directory.
            if ! echo "${JSON_CONTENT[@]}" | "$OP_SSH" -q "$VEHICLE_USER@$VEHICLE_ADDR" "$VEHICLE_CAT > $BIRTH_GEN_DIR/$VEHICLE_NAME.json"; then
                echo "Could not generate remote JSON file. Ensure the vehicle is accessible."
                exit 1
            fi

        else
            echo "Invalid value for '-l' or '--local' option. Legitimate values are: 'true' or 'false'; case-sensitive and without single-quotes."
            exit 1
        fi
    fi
}
