#!/bin/sh
#
# calculate in-core fingerprint via looking at the object file rather than
# running a program on the target
#

DEBUG=

OBJCOPY=${CROSS_COMPILE}objcopy
OBJDUMP=${CROSS_COMPILE}objdump

#OBJCOPY=objcopy
#OBJDUMP=objdump

HMAC_KEY="etaonrishdlcupfm"
FINGERTYPE="openssl sha1 -hmac ${HMAC_KEY}"

# FINGERTYPE can be made via openssl or fips_standalone_sha1 (output word 2)

# allow for a simple -d option
if [ "$1" = "-d" ]; then
  DEBUG=1
  shift
fi

if [ "$1" != "-exe" -a "$1" != "-dso" ]; then
  echo "usage: incore [-exe|-dso] executable" >&2
  exit 1
fi

APP="$2"

if [ -z "$APP" ]; then
  echo "usage: incore [-exe|-dso] executable" >&2
  exit 1
fi

if [ ! -f "$APP" ]; then 
  echo "incore: $APP not found" >&2
  exit 1
fi

#TARGET=elf64-x86-64
TARGET=`$OBJDUMP -f $APP | grep 'file format' | awk '{print $4}'`

if [ ! -z "$DEBUG" ]; then
  echo "TARGET: $TARGET" >&2
fi

# INCORE_ADJUST is the fixup allowance for FIPS_ref_point() handling in 
# fips/fips_canister.c which is used rather than the actual
# function address

if [ -z "$INCORE_ADJUST" ]; then

  INCORE_ADJUST=4
  case $TARGET in
    elf64-x86-64) INCORE_ADJUST=4;;
    #elf32-littlearm|elf32-little|elf32-bigarm) INCORE_ADJUST="-36";;
    elf32-littlearm|elf32-little|elf32-bigarm) INCORE_ADJUST="-8";;
  esac

fi

#$OBJCOPY  -j .rodata -v -O binary $APP $APP-rodata  | grep -v '^copy from'
#$OBJCOPY  -j .text -v -O binary $APP $APP-text | grep -v '^copy from'
#$OBJCOPY  -j .rodata -v -F $TARGET $APP $APP-rodata  | grep -v '^copy from'
#$OBJCOPY  -j .text -v -F $TARGET $APP $APP-text | grep -v '^copy from'

#
# locate all the required symbols
#
eval `$OBJDUMP -t $APP | egrep 'FIPS_text_start|FIPS_text_end|FIPS_rodata_end|FIPS_rodata_start|FIPS_signature|FINGERPRINT_ascii_value' | awk '{printf("%s=%s\n",$6,toupper($1))}' | sed -e 's/\./_/g'`

#
# locate the offsets and length of the interesting sections
#
eval `$OBJDUMP -h $APP | egrep '.text|.rodata|.bss' | awk '{printf("%s=%s\n%s_OFF=%s\n",$2,toupper($4),$2,toupper($6))}' | sed -e 's/^\./DOT/' -e 's/\./_/g'`

#
# should now have the following variables set which can be used to 
# extract the right parts from the -rodata and -text files
#
# e.g.
# FIPS_rodata_end=0000000000436160
# FIPS_rodata_start=0000000000430B00
# FIPS_signature=000000000063EBE0
# FIPS_text_end=00000000004304E0
# FIPS_text_start=0000000000401780
# DOTrodata=0000000000430AE0
# DOTrodata_OFF=00030AE0
# DOTtext=0000000000401690
# DOTtext_OFF=00001690

#
# show the values - debug
#
if [ ! -z "$DEBUG" ]; then
  (
  echo "FIPS_rodata_end=$FIPS_rodata_end"
  echo "FIPS_rodata_start=$FIPS_rodata_start"
  echo "FIPS_signature=$FIPS_signature"
  echo "FIPS_text_end=$FIPS_text_end"
  echo "FIPS_text_start=$FIPS_text_start"
  echo "FINGERPRINT_ascii_value=$FINGERPRINT_ascii_value"
  echo "DOTrodata=$DOTrodata"
  echo "DOTrodata_OFF=$DOTrodata_OFF"
  echo "DOTtext=$DOTtext"
  echo "DOTtext_OFF=$DOTtext_OFF"
  ) >&2 
fi

if [ -z "$FIPS_rodata_start" ]; then
  echo "$APP: Not a FIPS executable" >&2 
  exit 1
fi
if [ -z "$FIPS_rodata_end" ]; then
  echo "$APP: Not a FIPS executable" >&2 
  exit 1
fi
if [ -z "$FIPS_text_start" ]; then
  echo "$APP: Not a FIPS executable" >&2 
  exit 1
fi
if [ -z "$FIPS_text_end" ]; then
  echo "$APP: Not a FIPS executable" >&2 
  exit 1
fi

# 
# use 'bc' to calculate offsets and lengths for RODATA
# 
RSTART=`cat <<EOF | bc
obase=10
ibase=16 
$FIPS_rodata_start-$DOTrodata
EOF`
RLEN=`cat <<EOF | bc
obase=10
ibase=16 
$FIPS_rodata_end-$FIPS_rodata_start
EOF`
ROFF=`cat <<EOF | bc
obase=10
ibase=16 
$DOTrodata_OFF
EOF`
ROFF=`expr $ROFF + $RSTART`

# 
# use 'bc' to calculate offsets and lengths for TEXT
# 
TSTART=`cat <<EOF | bc
obase=10
ibase=16 
$FIPS_text_start-$DOTtext
EOF`
TLEN=`cat <<EOF | bc
obase=10
ibase=16 
$FIPS_text_end-$FIPS_text_start
EOF`
TOFF=`cat <<EOF | bc
obase=10
ibase=16 
$DOTtext_OFF
EOF`
TOFF=`expr $TOFF + $TSTART + $INCORE_ADJUST`

# 
# use 'bc' to calculate where to locate FINGERPRINT_ascii_value
# 
FSTART=`cat <<EOF | bc
obase=10
ibase=16 
$FINGERPRINT_ascii_value-$DOTrodata
EOF`
# 20 bytes as ASCII HEX
FLEN=40
FOFF=`cat <<EOF | bc
obase=10
ibase=16 
$DOTrodata_OFF
EOF`
FOFF=`expr $FOFF + $FSTART`

#
# NOTE: this code does not check for FIPS_signature being inside the 
#       rodata segment and exclude it from the calculation which is what
#       the actual runtime code does as we do not update it; the 
#       FIPS_signature should be in BSS - but in either case our calculation 
#       is correct as the signature comes from FINGERPRINT_ascii_value
#       when FIPS_signature is actually blank (zero)
#

#
# dump useful values
# 
if [ ! -z "$DEBUG" ]; then
  (
  echo "TSTART $TSTART"
  echo "TLEN $TLEN"
  echo "TOFF $TOFF"
  echo "INCORE_ADJUST $INCORE_ADJUST"

  echo "RSTART $RSTART"
  echo "RLEN $RLEN"
  echo "ROFF $ROFF"

  echo "FSTART $FSTART"
  echo "FLEN $FLEN"
  echo "FOFF $FOFF"
  ) >&2
fi

# some debug code when looking at the values
if [ ! -z "$INCORE_DEBUG" ]; then
  dd if=$APP of=mac1 bs=1 skip=$TOFF count=$TLEN
  dd if=$APP of=mac2 bs=1 skip=$ROFF count=$RLEN
  cat mac1 mac2 > mac
  $FINGERTYPE mac
fi

#
# show the actual value of FINGERPRINT_ascii_value as placed in 
# the program by fipsld
#
if [ ! -z "$DEBUG" ]; then
  (
  echo "embedded: "
  dd if=$APP bs=1 skip=$FOFF count=$FLEN  2>/dev/null
  echo 
  ) >&2
fi

#
# now calculate what that value should be from the appropriate sections
# of the object file
#
if [ ! -z "$DEBUG" ]; then
  echo "calculated: " >&2
fi
( dd if=$APP bs=1 skip=$TOFF count=$TLEN && \
  dd if=$APP bs=1 skip=$ROFF count=$RLEN ) 2>/dev/null | $FINGERTYPE

exit $?


