#!/usr/bin/env zsh # # Copyright (C) 2007-2016 Dyne.org Foundation # # Tomb test units by Denis Roio # # This source code is free software; you can redistribute it and/or # modify it under the terms of the GNU Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This source code is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Please refer # to the GNU Public License for more details. # # You should have received a copy of the GNU Public License along with # this source code; if not, write to: Free Software Foundation, Inc., # 675 Mass Ave, Cambridge, MA 02139, USA. T="../../tomb" source ${T} source dummypass=test dummypassnew=changetest GLOBAL_RESULT=0 notice() { print; _message "${@}"; print; } error() { _warning " ${@}"; } tt() { start_loops=(`sudo losetup -a |cut -d: -f1`) start_temps=(`find /dev/shm -name 'tomb*'`) ${T} -D ${=@} res=$? loops=(`sudo losetup -a |cut -d: -f1`) temps=(`find /dev/shm -name 'tomb*'`) { test "${#start_loops}" = "${#loops}" } || { error "loop device usage change to ${#loops}" } { test "${#start_temps}" = "${#temps}" } || { error "temp files usage change to ${#temps}" } print " Tomb command returns $res" return $res } # check for auxiliary programs KDF=1 STEGHIDE=1 RESIZER=1 command -v steghide > /dev/null || STEGHIDE=0 command -v e2fsck resize2fs > /dev/null || RESIZER=0 command -v tomb-kdb-pbkdf2 > /dev/null || KDF=0 command -v qrencode > /dev/null || QRENCODE=0 typeset -A results tests=(dig forge lock badpass open close passwd chksum bind setkey recip-dig recip-forge recip-lock recip-open recip-close recip-passwd recip-resize recip-setkey recip-default recip-hidden shared shared-passwd shared-setkey) { test $RESIZER = 1 } && { tests+=(resize) } { test $KDF = 1 } && { tests+=(kdforge kdfpass kdflock kdfopen) } { test $STEGHIDE = 1 } && { tests+=(stgin stgout stgopen stgpipe stgimpl recip-stgin recip-stgout recip-stgopen recip-stgimpl) } { test $QRENCODE = 1 } && { tests+=(qrenc) } # GnuPG Conf. # Note: the assumption is the test keys are unencrypted. export GNUPGHOME="gnupg/" chmod 700 "$GNUPGHOME" gpgid_1="A4857CD176B31435F9709D25F0E573B8289439CD" gpgid_2="0B2235E660753AB0475FB3E23DC836481F44B31E" notice "Loading test suite" # functions that can be called singularly test-tomb-create() { notice "wiping all test.tomb* in /tmp" sudo rm -f /tmp/test.tomb{,.key,.new.key} notice "Testing creation: dig" tt dig -s 20 /tmp/test.tomb { test $? = 0 } && { results+=(dig SUCCESS) } notice "Testing creation: forge" tt forge /tmp/test.tomb.key \ --ignore-swap --unsafe --tomb-pwd ${dummypass} { test $? = 0 } && { results+=(forge SUCCESS) # notice "Dump of clear key contents to examine them:" print ${dummypass} \ | gpg --batch --passphrase-fd 0 --no-tty --no-options -d /tmp/test.tomb.key \ | xxd echo -- } notice "Testing creation: lock" tt lock /tmp/test.tomb -k /tmp/test.tomb.key \ --ignore-swap --unsafe --tomb-pwd ${dummypass} { test $? = 0 } && { results+=(lock SUCCESS) } } test-tomb-recip() { notice "wiping all recip.tomb* in /tmp" local tomb=/tmp/recip.tomb local tomb_key=/tmp/recip.tomb.key sudo rm -f "$tomb" "$tomb_key" notice "Testing tomb with recipient creation: dig" tt dig -s 20 $tomb { test $? = 0 } && { results+=(recip-dig SUCCESS) } notice "Testing tomb with recipient creation: forge" tt forge $tomb_key -g -r $gpgid_1 --ignore-swap --unsafe { test $? = 0 } && { results+=(recip-forge SUCCESS) } notice "Testing tomb with recipient creation: lock" tt lock $tomb -k $tomb_key -g -r $gpgid_1 --ignore-swap --unsafe { test $? = 0 } && { results+=(recip-lock SUCCESS) } notice "Testing tomb with recipient opening: open" tt open $tomb -k $tomb_key -g { test $? = 0 } && { results+=(recip-open SUCCESS) } notice "Testing tomb with recipient closing: close" tt close recip { test $? = 0 } && { results+=(recip-close SUCCESS) } { test $STEGHIDE = 1 } && { notice "Testing tomb with recipient steganographic hiding of keys" cp -f arditi.jpg /tmp/recip.jpg sudo rm -f /tmp/recip.steg.key tt --unsafe --tomb-pwd ${dummypass} bury -k /tmp/recip.tomb.key \ /tmp/recip.jpg -g -r "$gpgid_1" { test $? = 0 } && { results+=(recip-stgin SUCCESS) } tt --unsafe --tomb-pwd ${dummypass} exhume -k /tmp/recip.steg.key \ /tmp/recip.jpg { test $? = 0 } && { results+=(recip-stgout SUCCESS) } tt --unsafe --tomb-pwd ${dummypass} open -k /tmp/recip.steg.key \ /tmp/recip.tomb -g { test $? = 0 } && { results+=(recip-stgopen SUCCESS) } ${T} close recip notice "test using open -k image.jpeg" tt --unsafe --tomb-pwd ${dummypass} open -k /tmp/recip.jpg \ /tmp/recip.tomb -g { test $? = 0 } && { results+=(recip-stgimpl SUCCESS) } tt close recip } notice "Testing tomb with recipient changing gpg key: passwd" res=0 tt passwd -k $tomb_key -g -r $gpgid_2 { test $? = 0 } || { res=1 } tt open $tomb -k $tomb_key -g { test $? = 0 } || { res=1 } tt close recip { test $? = 0 } || { res=1 } { test $res = 0 } && { results+=(recip-passwd SUCCESS) } notice "Testing tomb with recipient resizing a tomb: resize" tt resize -s 30 $tomb -k $tomb_key -g -r $gpgid_2 { test $? = 0 } && { results+=(recip-resize SUCCESS) } notice "Testing tomb with recipient setting a new key: setkey" sudo rm -f /tmp/new.recip.tomb.key res=0 tt forge /tmp/new.recip.tomb.key -g -r $gpgid_2 \ --ignore-swap --unsafe { test $? = 0 } || { res=1 } tt setkey -k /tmp/new.recip.tomb.key $tomb_key $tomb -g -r $gpgid_2 { test $? = 0 } || { res=1 } tt open -k /tmp/new.recip.tomb.key $tomb -g { test $? = 0 } || { res=1 } { test $res = 0 } && { results+=(recip-setkey SUCCESS) } tt close recip } test-tomb-recip-default() { notice "wiping all default.tomb* in /tmp" rm -f /tmp/default.tomb /tmp/default.tomb.key /tmp/default.tmp notice "Testing tomb with the default recipient" res=0 tt dig -s 20 /tmp/default.tomb { test $? = 0 } || { res=1 } tt forge /tmp/default.tomb.key -g --ignore-swap --unsafe { test $? = 0 } || { res=1 } tt lock /tmp/default.tomb -k /tmp/default.tomb.key \ --ignore-swap --unsafe -g { test $? = 0 } || { res=1 } gpg -d --status-fd 2 /tmp/default.tomb.key 1> /dev/null 2> /tmp/default.tmp [[ -z "$(grep 'Tomb Test 2' /tmp/default.tmp)" ]] && { res=1 } { test $res = 0 } && { results+=(recip-default SUCCESS) } } test-tomb-recip-hidden() { notice "wiping all hidden.tomb* in /tmp" rm -f /tmp/hidden.tomb /tmp/hidden.tomb.key notice "Testing tomb with hidden recipient" res=0 tt dig -s 20 /tmp/hidden.tomb { test $? = 0 } || { res=1 } tt forge /tmp/hidden.tomb.key -g -R $gpgid_1 --ignore-swap --unsafe { test $? = 0 } || { res=1 } tt lock /tmp/hidden.tomb -k /tmp/hidden.tomb.key \ --ignore-swap --unsafe -g -R $gpgid_1 { test $? = 0 } || { res=1 } { test $res = 0 } && { results+=(recip-hidden SUCCESS) } } test-tomb-shared() { notice "wiping all shared.tomb* in /tmp" rm -f /tmp/shared.tomb /tmp/shared.tomb.key notice "Testing sharing a tomb" res=0 tt dig -s 20 /tmp/shared.tomb { test $? = 0 } || { res=1 } tt forge /tmp/shared.tomb.key -g -r $gpgid_1,$gpgid_2 \ --ignore-swap --unsafe { test $? = 0 } || { res=1 } tt lock /tmp/shared.tomb -k /tmp/shared.tomb.key \ --ignore-swap --unsafe -g -r $gpgid_1 { test $? = 0 } || { res=1 } tt open /tmp/shared.tomb -k /tmp/shared.tomb.key -g { test $? = 0 } || { res=1 } tt close shared { test $? = 0 } || { res=1 } { test $res = 0 } && { results+=(shared SUCCESS) } notice "Testing changing recipients on a shared Tomb" tt passwd -k /tmp/shared.tomb.key -g -r $gpgid_2,$gpgid_1 { test $? = 0 } && { results+=(shared-passwd SUCCESS) } notice "Testing setkey on a shared Tomb" rm -f /tmp/new.shared.tomb.key res=0 tt forge /tmp/new.shared.tomb.key -g -r $gpgid_1,$gpgid_2 \ --ignore-swap --unsafe { test $? = 0 } || { res=1 } tt setkey -k /tmp/new.shared.tomb.key /tmp/shared.tomb.key /tmp/shared.tomb \ -g -r $gpgid_2,$gpgid_1 { test $? = 0 } || { res=1 } { test $res = 0 } && { results+=(shared-setkey SUCCESS) } } test-bind-hooks() { notice "Testing bind hooks" tt --ignore-swap --unsafe --tomb-pwd ${dummypass} \ open /tmp/test.tomb -k /tmp/test.tomb.key rnd=$RANDOM bindtest="dyne-tomb-bind-test-$rnd" echo $rnd > /media/test/$bindtest rm -f /media/test/bind-hooks echo "$bindtest $bindtest" > /media/test/bind-hooks touch $HOME/$bindtest tt close test tt -k /tmp/test.tomb.key --unsafe --tomb-pwd ${dummypass} open /tmp/test.tomb rnd2=`cat $HOME/$bindtest` if [ "$rnd" = "$rnd2" ]; then notice "Bind hook on file matches" results+=(bind SUCCESS) tt list test else error "Bind hook on file reports incongruence" fi tt close test } test-set-key() { notice "Testing set key" sudo rm -f /tmp/test.tomb.new.key tt forge -k /tmp/test.tomb.new.key --force --unsafe --tomb-pwd ${dummypass} tt setkey -k /tmp/test.tomb.new.key --unsafe --tomb-pwd ${dummypass} --tomb-old-pwd ${dummypass} /tmp/test.tomb.key /tmp/test.tomb tt open -k /tmp/test.tomb.new.key --unsafe --tomb-pwd ${dummypass} /tmp/test.tomb [[ $? = 0 ]] && { notice "Setkey succesfully swapped tomb key" results+=(setkey SUCCESS) notice "Dump of clear key contents to examine them:" print ${dummypass} \ | gpg --batch --passphrase-fd 0 --no-tty --no-options -d /tmp/test.tomb.new.key \ | xxd echo -- mv /tmp/test.tomb.new.key /tmp/test.tomb.key tt close test } } test-regression() { url=${1:-https://files.dyne.org/tomb/old-releases/Tomb-2.2.tar.gz} notice "Regression tests using $url" curl $url > /tmp/tomb-regression.tar.gz mkdir -p /tmp/tomb-regression tar xfz /tmp/tomb-regression.tar.gz \ --strip-components 1 -C /tmp/tomb-regression OLDT="/tmp/tomb-regression/tomb" version=`${OLDT} -v |& awk 'NR==1 {print $3}'` _message "tomb version: $version" tests+=(oldnew-$version newold-$version) sudo rm -f /tmp/regression-test.tomb{,.key} ${OLDT} -D dig -s 10 /tmp/regression-test.tomb ${OLDT} -D forge /tmp/regression-test.tomb.key \ --ignore-swap --unsafe --tomb-pwd ${dummypass} ${OLDT} -D lock /tmp/regression-test.tomb -k /tmp/regression-test.tomb.key \ --ignore-swap --unsafe --tomb-pwd ${dummypass} notice "opening old tomb and key using the new tomb" tt -k /tmp/regression-test.tomb.key --unsafe \ --tomb-pwd ${dummypass} open /tmp/regression-test.tomb [[ $? = 0 ]] && results+=(oldnew-$version SUCCESS) tt close regression-test notice "opening new tomb and key using the old tomb" ${OLDT} -D -k /tmp/test.tomb.key --unsafe \ --tomb-pwd ${dummypass} open /tmp/test.tomb [[ $? = 0 ]] && results+=(newold-$version SUCCESS) ${OLDT} close test } test-open-read-only() { notice "wiping all testro.tomb* in /tmp" sudo rm -f /tmp/testro.tomb{,.key,.new.key} # Create new tt dig -s 20 /tmp/testro.tomb tt forge /tmp/testro.tomb.key \ --ignore-swap --unsafe --tomb-pwd ${dummypass} tt lock /tmp/testro.tomb -k /tmp/testro.tomb.key \ --ignore-swap --unsafe --tomb-pwd ${dummypass} notice "Testing open read only" # Remove write privilege on test.tomb chmod -w /tmp/testro.tomb # Attempt to open the unwritable tomb with the read-only mount option tt open /tmp/testro.tomb -k /tmp/testro.tomb.key \ --ignore-swap --unsafe --tomb-pwd ${dummypass} -o ro,noatime,nodev { test $? = 0 } && { results+=(openro SUCCESS) tt close testro } } startloops=(`sudo losetup -a |cut -d: -f1`) [[ $1 = "source" ]] && { return 0 } [[ $1 = "" ]] || { tt ${=@} return $? } # isolated function (also called with source) test-tomb-create test-tomb-recip test-tomb-recip-default test-tomb-recip-hidden test-tomb-shared notice "Testing open with wrong password" tt -k /tmp/test.tomb.key --unsafe --tomb-pwd wrongpassword open /tmp/test.tomb { test $? = 0 } || { results+=(badpass SUCCESS) } notice "Testing open with good password" tt -k /tmp/test.tomb.key --unsafe --tomb-pwd ${dummypass} open /tmp/test.tomb { test $? = 0 } && { results+=(open SUCCESS) } tt close test { test $? = 0 } && { results+=(close SUCCESS) } # isolated function test-open-read-only notice "Testing changing tomb password" tt passwd /tmp/test.tomb \ -k /tmp/test.tomb.key --unsafe --tomb-old-pwd ${dummypass} --tomb-pwd ${dummypassnew} tt passwd /tmp/test.tomb \ -k /tmp/test.tomb.key --unsafe --tomb-old-pwd ${dummypassnew} --tomb-pwd ${dummypass} { test $? = 0 } && { results+=(passwd SUCCESS) } notice "Generating content for file integrity test" tt -k /tmp/test.tomb.key --unsafe --tomb-pwd ${dummypass} open /tmp/test.tomb tt dig -s 10 /media/test/datacheck.raw crc="sha256 /media/test/datacheck.raw" echo "$crc" > /media/test/datacheck.sha tt --unsafe close test { test $RESIZER = 1 } && { notice "Testing resize to 30 MiB" tt --unsafe --tomb-pwd ${dummypass} -k /tmp/test.tomb.key resize /tmp/test.tomb -s 30 { test $? = 0 } && { results+=(resize SUCCESS) } } notice "Testing contents integrity" tt -k /tmp/test.tomb.key --unsafe --tomb-pwd ${dummypass} open /tmp/test.tomb { test $? = 0 } && { crc2="sha256 /media/test/datacheck.raw" { test "$crc" = "$crc2" } && { results+=(chksum SUCCESS) } tt close test } # regression tests with previous stable versions test-regression https://files.dyne.org/tomb/old-releases/Tomb-2.2.tar.gz test-regression https://files.dyne.org/tomb/old-releases/Tomb-2.1.1.tar.gz test-regression https://files.dyne.org/tomb/old-releases/Tomb-2.0.1.tar.gz # isolated function test-bind-hooks # iso func test-set-key { test $KDF = 1 } && { notice "Testing KDF key" sudo rm -f /tmp/test.tomb.kdf /tmp/kdf.tomb tt --unsafe --tomb-pwd ${dummypass} --kdf 1 forge -k /tmp/test.tomb.kdf { test $? = 0 } && { results+=(kdforge SUCCESS) } tt passwd --unsafe --tomb-old-pwd ${dummypass} --tomb-pwd ${dummypassnew} --kdf 1 -k /tmp/test.tomb.kdf { test $? = 0 } && { results+=(kdfpass SUCCESS) } tt dig -s 10 /tmp/kdf.tomb tt lock /tmp/kdf.tomb -k /tmp/test.tomb.kdf \ --ignore-swap --unsafe --tomb-pwd ${dummypassnew} --kdf 1 { test $? = 0 } && { results+=(kdflock SUCCESS) } tt open /tmp/kdf.tomb -k /tmp/test.tomb.kdf \ --ignore-swap --unsafe --tomb-pwd ${dummypassnew} --kdf 1 { test $? = 0 } && { results+=(kdfopen SUCCESS) } ${T} close kdf } { test $STEGHIDE = 1 } && { notice "Testing steganographic hiding of keys" cp -f arditi.jpg /tmp/tomb.jpg sudo rm -f /tmp/test.steg.key tt --unsafe --tomb-pwd ${dummypass} bury -k /tmp/test.tomb.key /tmp/tomb.jpg { test $? = 0 } && { results+=(stgin SUCCESS) } rm -f /tmp/test.steg.key tt --unsafe --tomb-pwd ${dummypass} exhume -k /tmp/test.steg.key /tmp/tomb.jpg { test $? = 0 } && { results+=(stgout SUCCESS) } tt --unsafe --tomb-pwd ${dummypass} open -k /tmp/test.steg.key /tmp/test.tomb { test $? = 0 } && { results+=(stgopen SUCCESS) } ${T} close test # test piping keys using -k - tkey=`tt --unsafe --tomb-pwd ${dummypass} exhume /tmp/tomb.jpg` print "$tkey" | tt --unsafe --tomb-pwd ${dummypass} open -k - /tmp/test.tomb { test $? = 0 } && { results+=(stgpipe SUCCESS) } ${T} close test notice "test using open -k image.jpeg" tt --unsafe --tomb-pwd ${dummypass} open -k /tmp/tomb.jpg /tmp/test.tomb { test $? = 0 } && { results+=(stgimpl SUCCESS) } tt close test } { test $QRENCODE = 1 } && { notice "test rendering a QR printable key backup" tt engrave -k /tmp/test.tomb.key { test $? = 0 } && { results+=(qrenc SUCCESS) } } # rm /tmp/test.tomb{,.key} -f || exit 1 endloops=(`sudo losetup -a |cut -d: -f1`) notice "Test results summary" print "${#startloops} loop devices busy at start" for t in $tests; do res=${results[$t]:-FAIL} [[ "$res" == "SUCCESS" ]] || GLOBAL_RESULT=1 echo "$t\t$res" done print "${#endloops} loop devices busy at end" print "Done. You can remove temporary leftovers from /tmp :" for i in `find /tmp -name '*tomb*' 2>/dev/null`; do ls -lh $i; done return $GLOBAL_RESULT