#! /bin/bash
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

########################################################################
#
# mozilla/security/nss/tests/dbtest/dbtest.sh
#
# Certificate generating and handeling for NSS QA, can be included
# multiple times from all.sh and the individual scripts
#
# needs to work on all Unix and Windows platforms
#
# included from (don't expect this to be up to date)
# --------------------------------------------------
#   all.sh
#   ssl.sh
#   smime.sh
#   tools.sh
#
# special strings
# ---------------
#   FIXME ... known problems, search for this string
#   NOTE .... unexpected behavior
#
# FIXME - Netscape - NSS
########################################################################

############################## dbtest_init ###############################
# local shell function to initialize this script
########################################################################
dbtest_init()
{
  SCRIPTNAME="dbtests.sh"
  if [ -z "${CLEANUP}" ] ; then     # if nobody else is responsible for
      CLEANUP="${SCRIPTNAME}"       # cleaning this script will do it
  fi
  if [ -z "${INIT_SOURCED}" ] ; then
      cd ../common
      . ./init.sh
  fi
  if [ ! -r $CERT_LOG_FILE ]; then  # we need certificates here
      cd ../cert
      . ./cert.sh
  fi

  # normally we inherit this environment variable from cert.sh, but in the CI
  # tests, we run cert.sh once in a different test and then copy the results
  # for dbtests, so we try to  get the ROOTCERTSFILE ourself if it doesn't exits
  if [ ! "${ROOTCERTSFILE}" ] ; then
    ROOTCERTSFILE=`ls -1 ${LIBDIR}/*nssckbi.* | head -1`
  fi

  SCRIPTNAME="dbtests.sh"
  RONLY_DIR=${HOSTDIR}/ronlydir
  EMPTY_DIR=${HOSTDIR}/emptydir
  CONFLICT_DIR=${HOSTDIR}/conflictdir
  THREAD_DIR=${HOSTDIR}/threadir
  BIG_DIR=${HOSTDIR}/bigdir
  TRUST1_DIR=${HOSTDIR}/trust1dir
  R_TRUST1_DIR=../trust1dir
  TRUST2_DIR=${HOSTDIR}/trust2dir
  R_TRUST2_DIR=../trust2dir
  TRUST3_DIR=${HOSTDIR}/trust3dir
  R_TRUST3_DIR=../trust3dir
  TRUST4_DIR=${HOSTDIR}/trust4dir
  R_TRUST4_DIR=../trust4dir
  TRUST5_DIR=${HOSTDIR}/trust5dir
  R_TRUST5_DIR=../trust5dir
  CRAFTED_KEYDB_DIR=${HOSTDIR}/craftedkeydbdir
  R_CRAFTED_KEYDB_DIR=../craftedkeydbdir
  mkdir -p $TRUST1_DIR
  mkdir -p $TRUST2_DIR
  mkdir -p $TRUST3_DIR
  mkdir -p $TRUST4_DIR
  mkdir -p $TRUST5_DIR
  mkdir -p $CRAFTED_KEYDB_DIR

  cd ${TRUST1_DIR}
  certutil -N -d ${R_TRUST1_DIR} -f ${R_PWFILE}
  certutil -N -d ${R_TRUST2_DIR} -f ${R_PWFILE}
  certutil -N -d ${R_TRUST3_DIR} -f ${R_PWFILE}
  certutil -N -d ${R_TRUST4_DIR} -f ${R_PWFILE}
  certutil -N -d ${R_TRUST5_DIR} -f ${R_PWFILE}
  certutil -N -d ${R_CRAFTED_KEYDB_DIR} -f ${R_PWFILE}

  html_head "CERT and Key DB Tests"

}

############################## dbtest_cleanup ############################
# local shell function to finish this script (no exit since it might be
# sourced)
########################################################################
dbtest_cleanup()
{
  html "</TABLE><BR>"
  cd ${QADIR}
  chmod a+rw $RONLY_DIR
  . common/cleanup.sh
}

Echo()
{
    echo
    echo "---------------------------------------------------------------"
    echo "| $*"
    echo "---------------------------------------------------------------"
}

dbtest_trust()
{
    Echo "Create an old-style trust database"
    cd ${TRUST1_DIR}
    export NSS_TRUST_TYPE="NSS"
    certutil -A -n "TestCA" -t "TC,C,C" -f "$R_PWFILE" -d ${R_TRUST1_DIR} -i ${R_CADIR}/TestCA.ca.cert
    certutil -A -n "Alice" -t ",," -f "$R_PWFILE" -d ${R_TRUST1_DIR} -i ${R_ALICEDIR}/Alice.cert
    unset NSS_TRUST_TYPE
    dbtool -d ${R_TRUST1_DIR} | grep CKO_NSS_TRUST
    ret=$?
    html_msg $ret 0 "Create and old-style trust database"

    # make sure we can verify an old-style database still
    certutil -V -n "Alice" -u R -d ${R_TRUST1_DIR} -f "$R_PWFILE"
    ret=$?
    html_msg $ret 0 "Verify cert from and old-style DB"

    # create an override record that will superceed the old style record
    Echo "Create an new-style trust database"
    export NSS_TRUST_TYPE="PKCS"
    echo certutil -A -n "TestCA" -t "T,," -f "$R_PWFILE" -d ${R_TRUST2_DIR} -i ${R_CADIR}/TestCA.ca.cert
    certutil -A -n "TestCA" -t "T,," -f "$R_PWFILE" -d ${R_TRUST2_DIR} -i ${R_CADIR}/TestCA.ca.cert
    unset NSS_TRUST_TYPE
    dbtool -d ${R_TRUST2_DIR} | grep CKO_TRUST
    ret=$?
    html_msg $ret 0 "Create and newstyle trust database"

    # arrange to load both databases at the same time
    cat >> ${R_TRUST2_DIR}/pkcs11.txt << __EOF__

library=
name="Alice lib"
parameters="configdir='${R_TRUST1_DIR}'"
NSS=flags=internal,readonly trustOrder=80
__EOF__
    cat ${R_TRUST2_DIR}/pkcs11.txt
    # trust 1's token name once they are both loaded, use to to find the Alice cert to verify
    Trust1_Token="NSS Application Token 00000004"
    echo certutil -V -n "${Trust1_Token}:Alice" -u R -d ${R_TRUST2_DIR} -f "$R_PWFILE"
    certutil -V -n "${Trust1_Token}:Alice" -u R -d ${R_TRUST2_DIR} -f "$R_PWFILE"
    ret=$?
    html_msg $ret 255 "Verify cert should fail from and old-style DB with new style override"

    # modify the trust to the original db was untrusted and the new one is trusted
    export NSS_TRUST_TYPE="NSS"
    certutil -M -n "TestCA" -t "T,," -f "$R_PWFILE" -d ${R_TRUST1_DIR}
    # make sure we don't have any new style records in this databse
    dbtool -d ${R_TRUST1_DIR} | grep  CKO_TRUST
    ret=$?
    html_msg $ret 1 "Modify and old-style trust database"

    export NSS_TRUST_TYPE="PKCS"
    certutil -M -n "TestCA" -t "TC,C,C" -f "$R_PWFILE" -d ${R_TRUST2_DIR}
    # make sure we don't have any old style records in this databse
    dbtool -d ${R_TRUST2_DIR} | grep CKO_NSS_TRUST
    ret=$?
    html_msg $ret 1 "Modify and new-style trust database"
    unset NSS_TRUST_TYPE

    # now test the we now fail without the override
    echo certutil -V -n "Alice" -u R -d ${R_TRUST1_DIR} -f "$R_PWFILE"
    certutil -V -n "Alice" -u R -d ${R_TRUST1_DIR} -f "$R_PWFILE"
    ret=$?
    html_msg $ret 255 "Verify cert correctly fails from and old-style DB"

    # and the we succeed with the override
    echo certutil -V -n "${Trust1_Token}:Alice" -u R -d ${R_TRUST2_DIR} -f "$R_PWFILE"
    certutil -V -n "${Trust1_Token}:Alice" -u R -d ${R_TRUST2_DIR} -f "$R_PWFILE"
    ret=$?
    html_msg $ret 0 "Verify cert succeeds with new style override"

    # we can only run these tests if we have our builtins file
    if [ -n "${ROOTCERTSFILE}" ] ; then
        # Test overriding the built-ins
        # built-ins still use NSS trust, so we will try to override them with
        # PKCS trust we pick a cert we expect will be in builtins for a while.
        # If it's ever removed,  pick a different one.
        CATestCert="Amazon Root CA 1"
        TestToken="Builtin Object Token"
        OverrideTrust="T,,C"
        CATestCertName="${TestToken}:${CATestCert}"
        echo modutil -add "RootCerts" -libfile "${ROOTCERTSFILE}" -dbdir "${R_TRUST3_DIR}"
        echo | modutil -add "RootCerts" -libfile "${ROOTCERTSFILE}" -dbdir "${R_TRUST3_DIR}"
        certutil -L -h "$TestToken" -d "${R_TRUST3_DIR}" | grep "${CATestCert}"
        ret=$?
        html_msg $ret 0 "Load Builtins and list $CATestCert"

        # create the override
        export NSS_TRUST_TYPE="PKCS"
        echo certutil -M -n "${CATestCertName}" -t "$OverrideTrust" -d "${R_TRUST3_DIR}" -f "$R_PWFILE"
        certutil -M -n "${CATestCertName}" -t "$OverrideTrust" -d "${R_TRUST3_DIR}" -f "$R_PWFILE"
        ret=$?
        html_msg $ret 0 "Modify trust on $CATestCert to '$OverrideTrust'"
        unset NSS_TRUST_TYPE

        # verify the override
        certutil -L -h all -d "${R_TRUST3_DIR}" -f "${R_PWFILE}" | grep "${CATestCert}"
        cert=$(certutil -L -h "$TestToken" -d "${R_TRUST3_DIR}" -f "${R_PWFILE}" | grep "${CATestCert}")
        cert="${cert%"${cert##*[![:space:]]}"}"
        trust=${cert##* }
        echo "cert = |$cert| trust = |$trust|"
        test  "$trust" = "$OverrideTrust"
        ret=$?
        html_msg $ret 0 "Verify trust on $CATestCert is '$OverrideTrust'"

        # finagle the token order so that the builtins are processed before
        # the new token
        echo modutil -add "RootCerts" -libfile "${ROOTCERTSFILE}" -dbdir "${R_TRUST4_DIR}"
        echo | modutil -add "RootCerts" -libfile "${ROOTCERTSFILE}" -dbdir "${R_TRUST4_DIR}"
        certutil -L -h "$TestToken" -d "${R_TRUST4_DIR}" | grep "${CATestCert}"
        ret=$?
        html_msg $ret 0 "Load Builtins for trust4 and list $CATestCert"

        # use trust3 as an override
        cat >> ${R_TRUST4_DIR}/pkcs11.txt << __EOF__

library=
name="external trust"
parameters="configdir='${R_TRUST3_DIR}'"
NSS=flags=internal,readonly trustOrder=80
__EOF__
        certutil -L -h all -d "${R_TRUST4_DIR}" -f "${R_PWFILE}" | grep "${CATestCert}"
        cert=$(certutil -L -h "$TestToken" -d "${R_TRUST4_DIR}" -f "${R_PWFILE}" | grep "${CATestCert}")
        cert="${cert%"${cert##*[![:space:]]}"}"
        trust=${cert##* }
        echo "cert = |$cert| trust = |$trust|"
        test  "$trust" = "$OverrideTrust"
        ret=$?
        html_msg $ret 0 "Verify trust on $CATestCert is '$OverrideTrust' in trust4 db"

        # reproduce the steps in Bug 1984165
        export NSS_TRUST_TYPE="NSS"
        echo modutil -add "RootCerts" -libfile "${ROOTCERTSFILE}" -dbdir "${R_TRUST5_DIR}"
        echo | modutil -add "RootCerts" -libfile "${ROOTCERTSFILE}" -dbdir "${R_TRUST5_DIR}"

        echo certutil -M -n "${CATestCertName}" -t "" -d "${R_TRUST5_DIR}" -f "$R_PWFILE"
        certutil -M -n "${CATestCertName}" -t ",C," -d "${R_TRUST5_DIR}" -f "$R_PWFILE"
        certutil -L -h "$TestToken" -d "${R_TRUST5_DIR}" | grep "${CATestCert}"
        certutil -M -n "${CATestCertName}" -t "C,C," -d "${R_TRUST5_DIR}" -f "$R_PWFILE"
        unset NSS_TRUST_TYPE
        certutil -L -h "$TestToken" -d "${R_TRUST5_DIR}" | grep "${CATestCert}"
        cert=$(certutil -L -h "$TestToken" -d "${R_TRUST5_DIR}" -f "${R_PWFILE}" | grep "${CATestCert}")
        cert="${cert%"${cert##*[![:space:]]}"}"
        trust=${cert##* }
        echo "cert = |$cert| trust = |$trust|"
        test  "$trust" = "C,C,"
        ret=$?
        html_msg $ret 0 "Verify trust on $CATestCert is 'C,C,'"
    fi
}

dbtest_metaData()
{
    Echo "Create a specially-crafted key4.db file"
    cd ${CRAFTED_KEYDB_DIR}
    cat >> cmds << __EOF__
DROP TABLE metaData;
CREATE TABLE metaData (id, item1, item2);
INSERT INTO metaData VALUES('password',X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'');
INSERT INTO metaData VALUES('password',X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'');
__EOF__
    sqlite3 key4.db < cmds
    ret=$?
    html_msg $ret 0 "Create a specially-crafted key4.db file"

    Echo "Open the specially-crafted key4.db file without crashing"
    certutil -d . -L
    ret=$?
    html_msg $ret 0 "Open the specially-crafted key4.db file without crashing"
}

dbtest_main()
{
    cd ${HOSTDIR}

    Echo "test opening the database read/write in a nonexisting directory"
    ${BINDIR}/certutil -L -X -d ./non_existent_dir
    ret=$?
    if [ $ret -ne 255 ]; then
      html_failed "Certutil succeeded in a nonexisting directory $ret"
    else
      html_passed "Certutil didn't work in a nonexisting dir $ret"
    fi
    ${BINDIR}/dbtest -r -d ./non_existent_dir
    ret=$?
    if [ $ret -ne 46 ]; then
      html_failed "Dbtest readonly succeeded in a nonexisting directory $ret"
    else
      html_passed "Dbtest readonly didn't work in a nonexisting dir $ret"
    fi

    Echo "test force opening the database in a nonexisting directory"
    ${BINDIR}/dbtest -f -d ./non_existent_dir
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Dbtest force failed in a nonexisting directory $ret"
    else
      html_passed "Dbtest force succeeded in a nonexisting dir $ret"
    fi

    Echo "test opening the database readonly in an empty directory"
    mkdir $EMPTY_DIR
    ${BINDIR}/tstclnt -h ${HOST} -d $EMPTY_DIR
    ret=$?
    if [ $ret -ne 1 ]; then
      html_failed "Tstclnt succeded in an empty directory $ret"
    else
      html_passed "Tstclnt didn't work in an empty dir $ret"
    fi
    ${BINDIR}/dbtest -r -d $EMPTY_DIR
    ret=$?
    if [ $ret -ne 46 ]; then
      html_failed "Dbtest readonly succeeded in an empty directory $ret"
    else
      html_passed "Dbtest readonly didn't work in an empty dir $ret"
    fi
    rm -rf $EMPTY_DIR/* 2>/dev/null
    ${BINDIR}/dbtest -i -d $EMPTY_DIR
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Dbtest logout after empty DB Init loses key $ret"
    else
      html_passed "Dbtest logout after empty DB Init has key"
    fi
    rm -rf $EMPTY_DIR/* 2>/dev/null
    ${BINDIR}/dbtest -i -p pass -d $EMPTY_DIR
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Dbtest password DB Init loses needlogin state $ret"
    else
      html_passed "Dbtest password DB Init maintains needlogin state"
    fi
    rm -rf $EMPTY_DIR/* 2>/dev/null
    ${BINDIR}/certutil -D -n xxxx -d $EMPTY_DIR #created DB
    ret=$?
    if [ $ret -ne 255 ]; then
        html_failed "Certutil succeeded in deleting a cert in an empty directory $ret"
    else
        html_passed "Certutil didn't work in an empty dir $ret"
    fi
    rm -rf $EMPTY_DIR/* 2>/dev/null
    Echo "test force opening the database  readonly in a empty directory"
    ${BINDIR}/dbtest -r -f -d $EMPTY_DIR
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Dbtest force readonly failed in an empty directory $ret"
    else
      html_passed "Dbtest force readonly succeeded in an empty dir $ret"
    fi

    Echo "test opening the database r/w in a readonly directory"
    mkdir $RONLY_DIR
    cp -r ${CLIENTDIR}/* $RONLY_DIR
    chmod -w $RONLY_DIR $RONLY_DIR/*

    # On Mac OS X 10.1, if we do a "chmod -w" on files in an
    # NFS-mounted directory, it takes several seconds for the
    # first open to see the files are readonly, but subsequent
    # opens immediately see the files are readonly.  As a
    # workaround we open the files once first.  (Bug 185074)
    if [ "${OS_ARCH}" = "Darwin" ]; then
        cat $RONLY_DIR/* > /dev/null
    fi

    # skipping the next two tests when user is root,
    # otherwise they would fail due to rooty powers
    if [ $UID -ne 0 ]; then
      ${BINDIR}/dbtest -d $RONLY_DIR
    ret=$?
    if [ $ret -ne 46 ]; then
      html_failed "Dbtest r/w succeeded in a readonly directory $ret"
    else
      html_passed "Dbtest r/w didn't work in an readonly dir $ret"
    fi
    else
      html_passed "Skipping Dbtest r/w in a readonly dir because user is root"
    fi
    if [ $UID -ne 0 ]; then
      ${BINDIR}/certutil -D -n "TestUser" -d .
    ret=$?
    if [ $ret -ne 255 ]; then
      html_failed "Certutil succeeded in deleting a cert in a readonly directory $ret"
    else
      html_passed "Certutil didn't work in an readonly dir $ret"
    fi
    else
        html_passed "Skipping Certutil delete cert in a readonly directory test because user is root"
    fi

    Echo "test opening the database ronly in a readonly directory"

    ${BINDIR}/dbtest -d $RONLY_DIR -r
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Dbtest readonly failed in a readonly directory $ret"
    else
      html_passed "Dbtest readonly succeeded in a readonly dir $ret"
    fi

    Echo "test force opening the database  r/w in a readonly directory"
    ${BINDIR}/dbtest -d $RONLY_DIR -f
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Dbtest force failed in a readonly directory $ret"
    else
      html_passed "Dbtest force succeeded in a readonly dir $ret"
    fi

    Echo "ls -l $RONLY_DIR"
    ls -ld $RONLY_DIR $RONLY_DIR/*

    mkdir ${CONFLICT_DIR}
    Echo "test creating a new cert with a conflicting nickname"
    cd ${CONFLICT_DIR}
    pwd
    ${BINDIR}/certutil -N -d ${CONFLICT_DIR} -f ${R_PWFILE}
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Nicknane conflict test failed, couldn't create database $ret"
    else
      ${BINDIR}/certutil -A -n alice -t ,, -i ${R_ALICEDIR}/Alice.cert -d ${CONFLICT_DIR}
      ret=$?
      if [ $ret -ne 0 ]; then
        html_failed "Nicknane conflict test failed, couldn't import alice cert $ret"
      else
        ${BINDIR}/certutil -A -n alice -t ,, -i ${R_BOBDIR}/Bob.cert -d ${CONFLICT_DIR}
        ret=$?
        if [ $ret -eq 0 ]; then
          html_failed "Nicknane conflict test failed, could import conflict nickname $ret"
        else
          html_passed "Nicknane conflict test, could not import conflict nickname $ret"
        fi
      fi
    fi

    Echo "test importing an old cert to a conflicting nickname"
    # first, import the certificate
    ${BINDIR}/certutil -A -n bob -t ,, -i ${R_BOBDIR}/Bob.cert -d ${CONFLICT_DIR}
    # now import with a different nickname
    ${BINDIR}/certutil -A -n alice -t ,, -i ${R_BOBDIR}/Bob.cert -d ${CONFLICT_DIR}
    # the old one should still be there...
    ${BINDIR}/certutil -L -n bob -d ${CONFLICT_DIR}
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Nickname conflict test-setting nickname conflict incorrectly worked"
    else
      html_passed "Nickname conflict test-setting nickname conflict was correctly rejected"
    fi
    # import a token private key and make sure the corresponding public key is
    # created
    IMPORT_OPTIONS=""
    if [ -n "$NSS_DISABLE_DSA" ]; then
        IMPORT_OPTIONS="-D noDSA"
    fi
    Echo "Importing Token Private Key"
    echo "pk11importtest ${IMPORT_OPTIONS} -d ${CONFLICT_DIR} -f ${R_PWFILE}"
    ${BINDIR}/pk11importtest ${IMPORT_OPTIONS} -d ${CONFLICT_DIR} -f ${R_PWFILE}
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Importing Token Private Key does not create the corrresponding Public Key"
    else
      html_passed "Importing Token Private Key correctly creates the corrresponding Public Key"
    fi
    Echo "Importing Token Private Key without explicit public key"
    echo "pk11importtest -n ${IMPORT_OPTIONS} -d ${CONFLICT_DIR} -f ${R_PWFILE}"
    ${BINDIR}/pk11importtest -n ${IMPORT_OPTIONS} -d ${CONFLICT_DIR} -f ${R_PWFILE}
    ret=$?
    if [ $ret -ne 0 ]; then
      html_failed "Importing Token Private Key does not regenerate the corrresponding Public Key"
    else
      html_passed "Importing Token Private Key correctly regenerates the corrresponding Public Key"
    fi
    #
    # If we are testing an sqlite db, make sure we detect corrupted attributes.
    # This test only runs if 1) we have sqlite3 (the command line sqlite diagnostic
    # tool) and 2) we are using the sql database (rather than the dbm).
    #
    which sqlite3
    ret=$?
    KEYDB=${CONFLICT_DIR}/key4.db
    # make sure sql database is bing used.
    if [ ! -f ${KEYDB} ]; then
      Echo "skipping key corruption test: requires sql database"
    # make sure sqlite3 is installed.
    elif [ $ret -ne 0 ]; then
      Echo "skipping key corruption test: sqlite3 command not installed"
    else
      # we are going to mangle this key database in multiple tests, save a copy
      # so that we can restore it later.
      cp ${KEYDB} ${KEYDB}.save
      # dump the keys in the log for diagnostic purposes
      ${BINDIR}/certutil -K -d ${CONFLICT_DIR} -f ${R_PWFILE}
      # fetch the rsa and ec key ids
      rsa_id=$(${BINDIR}/certutil -K -d ${CONFLICT_DIR} -f ${R_PWFILE} | grep rsa | awk '{ print $4}')
      ec_id=$(${BINDIR}/certutil -K -d ${CONFLICT_DIR} -f ${R_PWFILE} | grep ' ec ' | awk '{ print $4}')
      # now loop through all the private attributes and mangle them one at a time
      for i in 120 122 123 124 125 126 127 128 011
      do
        Echo "testing if key corruption is detected in attribute $i"
        cp ${KEYDB}.save ${KEYDB}  # restore the saved keydb
        # find all the hmacs for this key attribute and mangle each entry
        sqlite3 ${KEYDB} ".dump metadata" |  sed -e "/sig_key_.*_00000$i/{s/.*VALUES('\\(.*\\)',[xX]'\\(.*\\)',NULL.*/\\1 \\2/;p;};d" | while read sig data
        do
          # mangle the last byte of the hmac
          # The following increments the last nibble by 1 with both F and f
          # mapping to 0. This mangles both upper and lower case results, so
          # it will work on the mac.
          last=$((${#data}-1))
          newbyte=$(echo "${data:${last}}" | tr A-Fa-f0-9 B-F0b-f0-9a)
          mangle=${data::${last}}${newbyte}
          echo "  amending ${sig} from ${data} to ${mangle}"
          # write the mangled entry, inserting with a key matching an existing
          # entry will overwrite the existing entry with the same key (${sig})
          sqlite3 ${KEYDB} "BEGIN TRANSACTION; INSERT INTO metaData VALUES('${sig}',X'${mangle}',NULL); COMMIT"
        done
        # pick the key based on the attribute we are mangling,
        # only CKA_VALUE (0x011) is not an RSA attribute, so we choose
        # ec for 0x011 and rsa for all the rest. We could use the dsa
        # key here, both CKA_VALUE attributes will be modifed in the loop above, but
        # ec is more common than dsa these days.
        if [ "$i" = "011" ]; then
            key_id=$ec_id
        else
            key_id=$rsa_id
        fi
        # now try to use the mangled key (try to create a cert request with the key).
        echo "${BINDIR}/certutil -R -k ${key_id} -s 'CN=BadTest, E=bad@mozilla.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US' -d ${CONFLICT_DIR} -f ${R_PWFILE} -a"
        ${BINDIR}/certutil -R -k ${key_id} -s 'CN=BadTest, E=bad@mozilla.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US' -d ${CONFLICT_DIR} -f ${R_PWFILE} -a
        ret=$?
        if [ ${ret} -eq 0 ]; then
          html_failed "Key attribute $i corruption not detected"
        else
          html_passed "Corrupted key attribute $i correctly disabled key"
        fi
      done
      cp ${KEYDB}.save ${KEYDB}  # restore the saved keydb
    fi


    if [ "${NSS_DEFAULT_DB_TYPE}" = "sql" ] ; then
      LOOPS=${NSS_SDB_THREAD_LOOPS-7}
      THREADS=${NSS_SDB_THREAD_THREADS-30}
      mkdir -p ${THREAD_DIR}
      Echo "testing for thread starvation while creating keys"
      ${BINDIR}/certutil -N -d ${THREAD_DIR} --empty-password
      ${BINDIR}/sdbthreadtst -l ${LOOPS} -t ${THREADS} -d ${THREAD_DIR}
      ret=$?
      case "$ret" in
      "0")
         html_passed "Successfully completed ${LOOPS} loops in ${THREADS} threads without failure."
         ;;
      "2")
         html_failed "sdbthreadtst failed for some environment reason (like lack of memory)"
         ;;
      "1")
         html_failed "sdbthreadtst failed do to starvation using ${LOOPS} loops and ${THREADS} threads."
         ;;
      *)
         html_failed "sdbthreadtst failed with an unrecognized error code."
      esac

      # now verify that we can quickly dump a database that has explicit
      # default trust values (generated by updating a dbm database with
      # to a sql database with and older version of NSS).
      mkdir -p ${BIG_DIR}
      cp ${QADIR}/dbtests/bigdb/* ${BIG_DIR}/
      echo "time certutil -K -d ${BIG_DIR} -f ${R_PWFILE}"
      dtime=$(time -p (certutil -K -d ${BIG_DIR} -f ${R_PWFILE}) 2>&1 1>/dev/null)
      echo "------------- time ----------------------"
      echo $dtime
      # now parse the real time to make sure it's subsecond
      RARRAY=($dtime)
      TIMEARRAY=(${RARRAY[1]//./ })
      echo "${TIMEARRAY[0]} seconds"
      test ${TIMEARRAY[0]} -lt 5
      ret=$?
      html_msg ${ret} 0 "certutil dump keys with explicit default trust flags"
    fi
}

################## main #################################################

dbtest_init
dbtest_main 2>&1
if using_sql; then
  dbtest_trust
  dbtest_metaData
fi
dbtest_cleanup
