#! /bin/sh
#set -x
#=========================================================================
# Copyright (C) GemTalk Systems 1986-2020.  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.
#
#
#
# $Id$
#
#=========================================================================

# 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

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

if [ "$1" = "" -o "$1" = "-h" ]; then
    usage
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`

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 "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"

if [ $EXTRACT_CERT -eq 1 ]; then
  CERT=`mktemp -u --tmpdir $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 >/dev/null 2>&1
  if [ $? -ne 0 -o ! -f $CERT ]; then
      echo "[Error]: Failed to extract certificate from backup file"
      exit 1
  fi
fi

# Extract the public key from the certificate
PKEY=`mktemp -u --tmpdir $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"
    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 --tmpdir $BACKUPBASE.sig.XXX.bin`
$GEMSTONE/bin/copydbf -Y $SIG $BACKUP >/dev/null 2>&1
if [ $? -ne 0 -o ! -f $SIG ]; then
    echo "[Error]: Failed to extract digital signature from backup file"
    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.
#
# On Linux we could use head -c -131072, but passing a negative number
# of bytes to head is not portable.

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

echo "[Info]: Invoking openssl to perform the digital signature verification:"
echo ""
head -c $SZ $BACKUP |$GEMSTONE/bin/openssl dgst -verify $PKEY $SSLDGST $SIGOPT -keyform PEM -signature $SIG
RESULT=$?
# cleanup
rm -f $SIG $PKEY

if [ $EXTRACT_CERT -eq 1 ]; then
    rm -f $CERT
fi

exit $RESULT
