* WGs marked with an * asterisk has had at least one new draft made available during the last 5 days

Idsigcheck Tool

Validate the signature for an Internet-Draft
Version: 1.5
Author:
Home | Changelog | Code | Download | Checksums | | Copyright

#!/bin/bash
#
# idsigcheck
#
#   Check and Internet-Draft signature stored in an external p7s file
#
#   The only argument is the file name of the Internet-Draft.  The
#   signature is stored in a separate file with the same name with a
#   p7s file extension.  Some examples:
#
#     Internet-Draft: draft-ietf-example-widgets-03.txt
#     Signature File: draft-ietf-example-widgets-03.txt.p7s
#
#     Internet-Draft: draft-ietf-example-widgets-03.ps
#     Signature File: draft-ietf-example-widgets-03.ps.p7s
#
#   OpenSSL version 1.0.0 or newer is required.  Some systems come with
#   an earlier version of already installed, and the --setup part of the
#   script allows the newer version to be referenced, even if it is a
#   directory that is not in the search path.
#
#   This script depends on the following:
#     awk
#     basename
#     canon
#     colrm
#     date
#     grep
#     mktemp
#     openssl (version 1.0.0 or newer)
#     uname
#     wget
#     which
#
# Written by Russ Housley on 16-May-2011.
# Modified by Russ Housley on 18-May-2011 to add --help and --setup.
# Modified by Russ Housley on 7-Jun-2011 to add --version.
# Modified by Russ Housley on 2-Nov-2013 to support the both the
#   COMODO and the AddTrust root certificates.  (Version 1.1)
# Modified by Russ Housley on 21-Mar-2015 to use the root certificate
#   bundle from the IETF web page and to use the canon routine for
#   more complete canonicalization.  (Version 1.2)
# Modified by Russ Housley on 26-Oct-2016 to use "which" instead of
#   "whereis" to get the first guess for the location of openssl, use
#   https when fetching the certificate bundle from the IETF website,
#   and perform the signature validation based on the time that the
#   signer put in the signing time attribute.  (Version 1.3)
# Modified by Russ Housley on 22-Jan-2018 to use canon version 1.0.5
#   so that text and HTML files that contain Unicode characters will
#   work properly.  Also, check signature on the canonical form of
#   HTML files. (Version 1.4)
# Modified by Russ Housley on 27-Mar-2018 to include -binary on the
#   OpenSSL command line when verifying the signature. (Version 1.5)
#
# --------------------------------------------------------------------
#
# Copyright 2011, 2013, 2015, 2016, 2018  Russ Housley <housley@vigilsec.com>
#  All rights reserved.
# 
# Redistribution and use, with or without modification, are permitted
# provided that the following conditions are met:
#  - Redistributions must retain the above copyright notice, this list
#    of conditions and the following disclaimer.
#  - Neither the name of the author nor the names of contributors may
#    be used to endorse or promote products derived from this software
#    without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY RUSS HOUSLEY ''AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL RUSS HOUSLEY BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

# Initialize variables
#
VERSION="1.5"
CONFDIR=$HOME/.$(basename $0)
OPENSSLCMD=$CONFDIR/opensslv1
ROOTCERTBUNDLE=$CONFDIR/rootcert.pem
OSNAME=$(uname -s)
TMPFILE=0

# Make sure one and only one parameter is provided
#
if [ $# -ne 1 ]
then
  echo "Internet-Draft file name not provided"
  echo
  echo "usage: $(basename $0) internet-draft-file-name"
  echo "       $(basename $0) --version"
  echo "       $(basename $0) --help"
  echo "       $(basename $0) --setup"
  exit 1
fi

# *******************************************************************
# Provide version
#
if [ "$1" = "--version" ]
then
  echo "Version $VERSION"
  exit 0
fi

# *******************************************************************
# Provide help
#
if [ "$1" = "--help" ]
then
  echo "usage: $(basename $0) internet-draft-file-name"
  echo "       $(basename $0) --version"
  echo "       $(basename $0) --help"
  echo "       $(basename $0) --setup"
  echo
  echo "Validate the signature for an Internet-Draft.  The only"
  echo "argument is the file name of the Internet-Draft.  The"
  echo "signature is stored in a separate file with the same name"
  echo "with a .p7s file extension.  Some examples:"
  echo
  echo "  Internet-Draft: draft-ietf-example-widgets-03.txt"
  echo "  Signature File: draft-ietf-example-widgets-03.txt.p7s"
  echo
  echo "  Internet-Draft: draft-ietf-example-widgets-03.xml"
  echo "  Signature File: draft-ietf-example-widgets-03.xml.p7s"
  echo
  echo "  Internet-Draft: draft-ietf-example-widgets-03.ps"
  echo "  Signature File: draft-ietf-example-widgets-03.ps.p7s"
  echo
  echo "Options:"
  echo "  --version  Provide version"
  echo "  --help     Provide this help"
  echo "  --setup    Set configuration stored in ~/.$(basename $0)"
  exit 0
fi

# *******************************************************************
# Perform setup of configuration directory
#
if [ "$1" = "--setup" ]
then
  echo "making .idsigcheck"
  mkdir -p $CONFDIR

  # See if canon is installed
  #
  canon --version
  CANONVER=$(canon --version 2>&1 )
  if [ -z "${CANONVER}" ]
  then
    echo "Cannot find the canon.  Please install canon on the search path."
  else
    if ! [ ${CANONVER:6:3} = "1.0" ] || ! [ ${CANONVER:10:1} -ge "5" ]
    then
      echo "You have an old version of canon.  Please get 1.0.5 or newer."
    fi
  fi

  # See if openssl is installed and new enough
  #
  OPENSSLCMD=$(which "openssl")
  if [ -z "${OPENSSLCMD}" ]
  then
    DONE=0
  else
    VERSION=$($OPENSSLCMD version 2>&1)
    if [ "${VERSION:0:10}" = "OpenSSL 1." ]
    then
      ln -f -s "$OPENSSLCMD" "$CONFDIR/opensslv1"
      echo "Configured to use $OPENSSLCMD"
      echo "$VERSION"
      DONE=1
    else
      DONE=0
    fi
  fi

  # If not, get the full path name for the openssl
  #
  while [ $DONE -eq 0 ]
  do
    echo "OpenSSL is required. OpenSSL version must be 1.0.0 or newer."
    echo "Please provide the full path to the openssl command:"
    read OPENSSLCMD
    if [ -f "$OPENSSLCMD" ]
    then
      VERSION=$($OPENSSLCMD "version")
      if [ "${VERSION:0:10}" = "OpenSSL 1." ]
      then
        ln -f -s "$OPENSSLCMD" "$CONFDIR/opensslv1"
        echo "Configured to use $OPENSSLCMD"
        echo "$VERSION"
        DONE=1
      else
        echo "Bad version: $VERSION."
        echo
      fi
    else
      echo "File not found."
      echo
    fi
  done

  # Fetch the root certificate bundle from the IETF web site
  #
  wget -O $ROOTCERTBUNDLE https://www.ietf.org/id-info/verifybundle.pem 2> /dev/null
  if ( [ $? -eq 0 ] && [ -f $ROOTCERT ] )
  then
    echo "Root certificate bundle fetched from the IETF web site."
  else
    echo "Unable to use wget to obtain the root certificate bundle from the IETF"
    echo "web site. Manually fetch http://www.ietf.org/id-info/verifybundle.pem"
    echo "and store the file as ~/.$(basename $0)/rootcert.pem."
  fi

  exit 0
fi

# *******************************************************************
# Perform signature validation
#
if ( [ -f "$ROOTCERTBUNDLE" ] && [ -h "$OPENSSLCMD" ] )
then
  if [ -r "$1" ]
  then
    if [ -r "$1.p7s" ]
    then

      # Extract the signing time from the .p7s file
      #
      SIGNTIMESTRING=$(openssl cms -print -cmsout -noout -inform DER -in "$1.p7s" | \
          grep -A 2 "1.2.840.113549.1.9.5" | awk "NR%3==0" | colrm 1 22)

      # Convert the signing time to an epoch
      #
      # This is more complex than one might expect because BSD-like systems
      # and Linux-like systems have different date commands.  So be it.
      #
      case $OSNAME in
        *BSD|Darwin)
          SIGNTIMEEPOCH=$(date -j -f "%b %d %T %Y %Z" "$SIGNTIMESTRING" "+%s")
          ;;
        Linux)
          SIGNTIMEEPOCH=$(date -d "$SIGNTIMESTRING" "+%s")
          ;;
        *)
          echo "ERROR: Unknown system type: $OSNAME" >&2
          exit 3
          ;;
      esac

      # If the input is a .txt file or .html file, then canonicalize it,
      # otherwise use use the file without change
      #
      if [ $(basename "$1" .txt ) = $(basename "$1") ] &&
         [ $(basename "$1" .html) = $(basename "$1") ]
      then
        CONTENTFILE="$1"
      else
        TMPFILE=1
        CONTENTFILE=$(mktemp -q /tmp/$(basename "$0").XXXXXXXX)
        if [ $? -ne 0 ]
        then
          echo "$(basename $0): Unable to create temporary file, exiting..."
          exit 2
        fi
        CANONVER=$(canon --version 2>&1 )
        if ! [ ${CANONVER:6:3} = "1.0" ] || ! [ ${CANONVER:10:1} -ge "5" ]
        then
          echo "You have an old version of canon.  You need 1.0.5 or newer.  Exiting..."
          exit 6
        fi
        canon "$1" "$CONTENTFILE"
      fi

      # Check the signature
      #
      $OPENSSLCMD cms -verify -CAfile "$ROOTCERTBUNDLE" -content "$CONTENTFILE" \
          -inform DER -in "$1.p7s" -binary -attime "$SIGNTIMEEPOCH" -out /dev/null

    else
      echo "$1.p7s" not found
      exit 5
    fi
  else
    echo "$1" not found
    exit 4
  fi
else
  echo "$(basename $0): Not configured properly.  Run $(basename $0) --setup"
  exit 3
fi

# If a temp file was used, delete it
#
if [ $TMPFILE -eq 1 ]
then
  rm $CONTENTFILE
fi
Latest update: 2018-03-27 12:51 PDT - webmaster@tools.ietf.org