#! /bin/sh
#set -xv
#=========================================================================
# Copyright (C) GemTalk Systems 1986-2024.  All Rights Reserved.
#
# Name - verify_backup_with_openssl.sh
#
#  Example shell script to illustrate how to use openssl to verify the
#  digital signature of a secure full backup file.
#
#  In order to verify the signature in the backup, a verification
#  certificate is required. The certificate provided should come from
#  a trusted location, such as the secure key ring on the server.
#
#  If a known-good certificate is not available, verification may be
#  performed using the certificate stored in the backup file. This
#  method of verification is INSECURE and does not assure the backup
#  file has not been forged or altered.
#
#=========================================================================

usage(){
    NAME=`basename $0`
    echo "Usage:"
    echo "  $NAME <backupFile> <certFile>"
    echo "    -- verify the signature in the secure backup <backupFile> using certificate <certFile>"    
    echo "  $NAME <backupFile>"
    echo "    -- verify the signature in the secure backup <backupFile> using the certificate"
    echo "       inside the backup file. ** INSECURE **"
    exit 1
}

if [ "$1" = "" -o "$1" = "-h" ]; then
    usage
fi

# must have $GEMSTONE
if [ "a$GEMSTONE" = "a" ]; then
  echo "ERROR: GemStone scripts require a GEMSTONE environment variable."
  echo "       Please set it to the directory where GemStone resides."
  exit 1
fi

if [ "$2" != "" ]; then
    EXTRACT_CERT=0
    if [ ! -f "$2" ]; then
	echo "Certificate file $2 does not exit"
	exit 1
    fi
    CERT=$2
    echo "[Info]: Using certificate file $CERT"
else
    EXTRACT_CERT=1
    echo "[Warning]: Digital signature verification will be performed using the public key from the certificate stored in the backup file."
    echo "[Warning]: This verification method is insecure!"
fi

	
BACKUP=$1
BACKUPBASE=`basename $BACKUP`
BACKUP_FULL=`readlink -f $BACKUP`

if [ ! -f "$BACKUP" ]; then
    echo "[Error]: Cannot open backup file $BACKUP"
    exit 1
fi
# Make sure the file is a secure backup
$GEMSTONE/bin/copydbf -i $BACKUP |grep -i "Secure Backup" >/dev/null 2>&1
if [ $? -ne 0 ]; then
    echo "[Error]: File $BACKUP does not appear to be a secure backup file"
    exit 1
fi

# ensure a minimal path
if [ "x$PATH" = "x" ]; then PATH=:/bin:/usr/bin:/usr/ucb; export PATH; fi 

# Get the digest kind from the backup
RAWDIGEST=`$GEMSTONE/bin/copydbf -i $BACKUP |grep "Signature Hash" |awk '{ print $3 }'`
if [ "$RAWDIGEST" = "SHA-256" ]; then
    SSLDGST="-sha256"
elif [ "$RAWDIGEST" = "SHA-384" ]; then
    SSLDGST="-sha384"
elif [ "$RAWDIGEST" = "SHA-512" ]; then
    SSLDGST="-sha512"
else
    echo "[Error]: Unable to determine digest kind from $RAWDIGEST"
    exit 1
fi

echo "[Info]: Digest kind is $RAWDIGEST"


HERE=`pwd`
TEMPDIR=`mktemp -d`
if [ $? -ne 0 -o ! -d $TEMPDIR ]; then
    echo "[Error]: Failed to create temp directory"
    exit 1
fi
cd $TEMPDIR

if [ $EXTRACT_CERT -eq 1 ]; then
  CERT=`mktemp -u $BACKUPBASE.cert.XXX.pem`
  # Extract the verification certificate. We should be using a known-good
  # certificate from our key ring here instead!
  $GEMSTONE/bin/copydbf -X $CERT $BACKUP_FULL >/dev/null 2>&1
  if [ $? -ne 0 -o ! -f $CERT ]; then
      echo "[Error]: Failed to extract certificate from backup file"
      cd $HERE
      exit 1
  fi
fi

# Extract the public key from the certificate
PKEY=`mktemp -u $BACKUPBASE.pkey.XXX.pem`
$GEMSTONE/bin/openssl x509 -in $CERT -pubkey -noout -out $PKEY >/dev/null 2>&1
if [ $? -ne 0 -o ! -f $PKEY ]; then
    echo "[Error]: Failed to extract public key from certificate"
    cd $HERE
    exit 1
fi

$GEMSTONE/bin/openssl x509 -in $CERT -noout -text |grep rsaEncryption  >/dev/null 2>&1
if [ $? -eq 0 ]; then
    RSA=1
    SIGOPT="-sigopt rsa_padding_mode:pss"
else
    RSA=0
    SIGOPT=""
fi
       
# extract the signature from the backup file
SIG=`mktemp -u $BACKUPBASE.sig.XXX.bin`
$GEMSTONE/bin/copydbf -Y $SIG $BACKUP_FULL >/dev/null 2>&1
if [ $? -ne 0 -o ! -f $SIG ]; then
    echo "[Error]: Failed to extract digital signature from backup file"
    cd $HERE
    exit 1
fi

# Compute number of bytes to pipe to openssl.
# Tne entire backup file is signed except for the last 128K, which is
# the record that contains the signature itself.
#

# Get file size
SZ=`wc -c $BACKUP_FULL |awk '{ print $1 }'`
# Compute size of signed portion.
SZ=`expr $SZ - 131072`

echo "[Info]: Invoking openssl to perform the digital signature verification:"
echo ""

# Solaris head does not have -c
#
# AIX head does not handle binary data properly, so we split
# the backup file in 2 temporary files and pass the first (the signed part
# of the backup file) to openssl to verify.
#
OS=`uname -s`
if [ "$OS" = "AIX" -o "$OS" = "SunOS" ]; then
    split -b $SZ $BACKUP_FULL 
    RESULT=$?
    if [ $? -ne 0 -o ! -f "xaa" ]; then
	echo "[Error]: Failed to split backup file"
	cd $HERE
	exit 1
    fi
    $GEMSTONE/bin/openssl dgst -verify $PKEY $SSLDGST $SIGOPT -keyform PEM -signature $SIG xaa
else
    head -c $SZ $BACKUP_FULL | $GEMSTONE/bin/openssl dgst -verify $PKEY $SSLDGST $SIGOPT -keyform PEM -signature $SIG
fi
RESULT=$?
# cleanup
cd $HERE
rm -fr $TEMPDIR >/dev/null
exit $RESULT
