diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 74b2e59..8bf38bd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,5 +11,4 @@ e2e-test-job: stage: test image: localhost:5000/mta:latest script: - - bash /usr/bin/prepare.sh - - cd e2e-tests && bash runner.sh + - bash /usr/bin/prepare.sh && bash /opt/husk/mapped/e2e-tests/runner.sh diff --git a/docker/MTAContainerFile b/docker/MTAContainerFile index f59b8b2..e4f4e59 100644 --- a/docker/MTAContainerFile +++ b/docker/MTAContainerFile @@ -52,10 +52,13 @@ RUN apt-get update -yqq && \ openssh-client \ sudo \ postfix \ + postfix-pcre \ rsyslog \ postgresql \ openssl \ - sq + sq \ + bind9-host \ + inotify-tools RUN adduser --shell /bin/bash --disabled-password --gecos "" hockeypuck diff --git a/docker/mta_provision/etc/postfix/main.cf b/docker/mta_provision/etc/postfix/main.cf index d511997..083eb2f 100644 --- a/docker/mta_provision/etc/postfix/main.cf +++ b/docker/mta_provision/etc/postfix/main.cf @@ -41,9 +41,9 @@ myhostname = example.com myorigin = example.com alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases -mydestination = $myhostname, localhost.localdomain, localhost +mydestination = $myhostname, localhost.localdomain, localhost, example.com, example.org #relayhost = -mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 192.168.1.0/24 +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 0.0.0.0/0 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all diff --git a/docker/mta_provision/opt/husk/config.toml b/docker/mta_provision/opt/husk/config.toml index 0f983d9..f37141f 100644 --- a/docker/mta_provision/opt/husk/config.toml +++ b/docker/mta_provision/opt/husk/config.toml @@ -4,4 +4,24 @@ sequoia_home = "/tmp/sq_home" logfile_config = "./log4rs.yml" -keyservers = [ "hkps://example.com" ] +keyservers = [ "hkp://example.com" ] + +[logging.appenders.console] +kind = "console" +[logging.appenders.console.encoder] +pattern = "{d(%Y-%m-%d %H:%M:%S)(local)} {h({l})} [{t}] {m}{n}" + +[logging.appenders.file] +kind = "file" +path = "/tmp/husk.log" + +[logging.appenders.file.encoder] +pattern = "{d(%Y-%m-%d %H:%M:%S)(local)} {h({l})} [{t}] {m}{n}" + +[logging.root] +level = "debug" +appenders = ["file"] + +[logging.loggers."husk"] +level = "debug" + diff --git a/docker/mta_provision/usr/bin/gen_hockeypuck_conf.sh b/docker/mta_provision/usr/bin/gen_hockeypuck_conf.sh index fc3dffc..e749c04 100755 --- a/docker/mta_provision/usr/bin/gen_hockeypuck_conf.sh +++ b/docker/mta_provision/usr/bin/gen_hockeypuck_conf.sh @@ -35,7 +35,7 @@ webroot="/var/www/" bind="$IP:11371" [hockeypuck.hkps] -bind="$IP:443" +bind="$IP:4443" logRequestDetails=false cert="$CERTS/$DOMAIN.crt" key="$CERTS/$DOMAIN.key" diff --git a/docker/mta_provision/usr/bin/gen_sq_home.sh b/docker/mta_provision/usr/bin/gen_sq_home.sh index 2791391..bbf18b9 100644 --- a/docker/mta_provision/usr/bin/gen_sq_home.sh +++ b/docker/mta_provision/usr/bin/gen_sq_home.sh @@ -24,8 +24,8 @@ sq key export --cert $ALICE_FPR > $TMP/alice_sk.pgp sq key export --cert $CA_FPR > $TMP/ca_sk.pgp # only certs sq cert export --cert $BOB_FPR > $TMP/bob_pk.pgp -sq network keyserver publish --server hkps://example.com --cert $CAROL_FPR -sq network keyserver publish --server hkps://example.com --cert $DAVE_FPR +sq network keyserver publish --server hkp://example.com --cert $CAROL_FPR +sq network keyserver publish --server hkp://example.com --cert $DAVE_FPR # create store export SEQUOIA_HOME=$SEQUOIA_TARGET @@ -41,4 +41,3 @@ sq pki link authorize --unconstrained --cert $CA_FPR --all --domain example.com # bob@example.com has a local cert, which is certified by ca@example.com # carol@example.com is published on a keyserver and certified by ca@example.com # dave@example.com is published on a keyserver but uncertified - diff --git a/docker/mta_provision/usr/bin/prepare.sh b/docker/mta_provision/usr/bin/prepare.sh index 26bb6aa..5e4cdfc 100755 --- a/docker/mta_provision/usr/bin/prepare.sh +++ b/docker/mta_provision/usr/bin/prepare.sh @@ -3,29 +3,32 @@ BRANCH=$1 ## create domain -echo "127.0.0.1 " $(hostname) > /etc/hosts +echo "127.0.0.1 " $(hostname) >> /etc/hosts echo "127.0.0.2 example.com" >> /etc/hosts +echo "127.0.0.3 example.org" >> /etc/hosts ## build milter if [ -f /opt/husk/mapped/Cargo.toml ] ; then - HUSK_BIN=/opt/husk/mapped/target/release/husk -else + HUSK_BIN=/opt/husk/mapped/target/debug/husk + HUSK_DIR=/opt/husk/mapped/ +else cd /opt/husk git clone https://gitlab.com/husk-project/husk-milter.git cd husk-milter if [ "$BRANCH" != "" ] ; then git checkout $BRANCH fi - cargo build --release + cargo build - HUSK_BIN=/opt/husk/husk-milter/target/release/husk + HUSK_BIN=/opt/husk/husk-milter/target/debug/husk + HUSK_DIR=/opt/husk/husk-milter/ fi ## start rsyslogd /usr/sbin/rsyslogd -n -iNONE & ## start postfix -sudo postfix start +sudo postfix start ## start and prepare postgres DOMAINS="example.com" @@ -52,5 +55,14 @@ done bash /usr/bin/gen_sq_home.sh ## start milter -cd /opt/husk -$HUSK_BIN config.toml & +cd $HUSK_DIR/config +$HUSK_BIN daemon start --config config.toml & + +## extract SEQUOIA_HOME from the configuration +SEQUOIA_HOME=$(grep "sequoia_home" config.toml | cut -d '=' -f 2 | tr -d ' ') + +cat << EO_ENV > /tmp/env.sh +export HUSK_BIN=$HUSK_BIN +export HUSK_DIR=$HUSK_DIR +export SEQUOIA_HOME=$SEQUOIA_HOME +EO_ENV diff --git a/docker/mta_provision/usr/bin/test_1.sh b/docker/mta_provision/usr/bin/test_1.sh index d09759a..d7cbfc7 100644 --- a/docker/mta_provision/usr/bin/test_1.sh +++ b/docker/mta_provision/usr/bin/test_1.sh @@ -1,19 +1,20 @@ #!/usr/bin/bash -echo "test message" | sendmail -t root@example.com +adduser --shell /bin/bash --disabled-password --gecos "" mtatest +echo "test message" | sendmail -t mtatest@example.com sleep 1 ## simple test if mail passes -if [ -f /var/mail/root ] ; then +if [ -f /var/mail/mtatest ] ; then echo "success" - rm /var/mail/root + rm /var/mail/mtatest else echo "failure" exit 1 fi ## test encryption -## bob@example.com has an authenticated certificate in +## bob@example.com has an authenticated certificate in ## the cert store echo "test message" | sendmail -t bob@example.com sleep 1 diff --git a/e2e-tests/common.sh b/e2e-tests/common.sh new file mode 100644 index 0000000..2ec7c30 --- /dev/null +++ b/e2e-tests/common.sh @@ -0,0 +1,66 @@ +#!/usr/bin/bash + +# create a unix (shell) user +create_unix_user() { # name + adduser --quiet --shell /bin/bash --disabled-password --gecos "" $1 > /dev/null 2>&1 +} + +# delete a unix user, plus remove $HOME and mails +delete_unix_user() { # name + deluser --remove-home $1 +} + +# send a mail and wait for delivery +send_test_mail() { # email_address + echo "test mail" | sendmail $1 + inotifywait -qq -t 3 -e close_write /var/mail +} + +# test header +test_header() { # text + echo "##############################################" + echo $1 + echo "Workdir: $WORKDIR" + echo "##############################################" +} + +# Generate a key outside the cert store. The key will not be +# authenticated. +gen_key() { # email + FILE=$(echo $1 | cut -f 1 -d '@') + FPR=$(sq key generate --home none --shared-key --without-password \ + --email $1 \ + --output $WORKDIR/${FILE}_sk.pgp \ + --rev-cert $WORKDIR/${FILE}.rev |& grep "Fingerprint:" | cut -d ':' -f 2) + echo $FPR +} + +expect_mail() { # unix_user mode + if [ -f /var/mail/$1 ] ; then + case $2 in + encrypted) + if grep -q "BEGIN PGP MESSAGE" /var/mail/$1 ; then + R=0 + else + echo "expected encrypted mail for $1" >&2 + R=1 + fi + ;; + unencrypted) + if grep -q "BEGIN PGP MESSAGE" /var/mail/$1 ; then + echo "expected unencrypted mail for $1" >&2 + R=1 + else + R=0 + fi + ;; + delivered) + R=0 + ;; + esac + else + echo "no mail for $1" >&2 + R=1 + fi + echo $R +} diff --git a/e2e-tests/local_run.sh b/e2e-tests/local_run.sh index 59003c5..184f94f 100644 --- a/e2e-tests/local_run.sh +++ b/e2e-tests/local_run.sh @@ -1,10 +1,10 @@ #!/usr/bin/bash -cargo build --release +cargo build docker run -ti \ --rm \ --mount type=bind,src=$(pwd),dst=/opt/husk/mapped/ \ - localhost/mta \ - bash -c "/usr/bin/prepare.sh && bash /opt/husk/mapped/e2e-tests/runner.sh" + localhost/mta:latest \ + bash -c "/usr/bin/prepare.sh && bash /opt/husk/mapped/e2e-tests/runner.sh && bash -i" diff --git a/e2e-tests/runner.sh b/e2e-tests/runner.sh index 75e1a55..7bf5c22 100755 --- a/e2e-tests/runner.sh +++ b/e2e-tests/runner.sh @@ -1,21 +1,25 @@ #!/usr/bin/bash +. /tmp/env.sh +echo "bin:" $HUSK_BIN +echo "home:" $SEQUOIA_HOME + cd $(dirname $0) for TEST in ./tests/* ; do + # create a new WORKDIR + export WORKDIR=$(mktemp -d) + if bash $TEST ; then - echo "success" + echo "SUCCESS" else - echo "failure" - - # post mortem - echo "ls -l /var/mail" - ls -l /var/mail - echo "mailq" - mailq - echo "host example.com" - host example.com + echo "FAILURE" + # post mortem, leave WORKDIR intact for inspection + cat /tmp/husk.log exit 1 fi + + # remove WORKDIR + rm -rf $WORKDIR done diff --git a/e2e-tests/tests/10_basic.sh b/e2e-tests/tests/10_basic.sh index adadf44..7724c66 100644 --- a/e2e-tests/tests/10_basic.sh +++ b/e2e-tests/tests/10_basic.sh @@ -1,18 +1,15 @@ #!/usr/bin/bash -echo "Basic: Test if MTA is working" +# source some functions +. common.sh -adduser --shell /bin/bash --disabled-password --gecos "" mtatest -echo "test mail" | sendmail mtatest@example.com +test_header "Basic: Test if MTA is working" -sleep 1 +create_unix_user mtatest +send_test_mail mtatest@example.com -if [ -f /var/mail/mtatest ] ; then - RESULT_CODE=0 -else - RESULT_CODE=1 -fi +RESULT_CODE=$(expect_mail mtatest delivered) -deluser --remove-home mtatest +delete_unix_user mtatest exit $RESULT_CODE diff --git a/e2e-tests/tests/20_simple_encrypt.sh b/e2e-tests/tests/20_simple_encrypt.sh index 305b28b..6563d87 100644 --- a/e2e-tests/tests/20_simple_encrypt.sh +++ b/e2e-tests/tests/20_simple_encrypt.sh @@ -1,25 +1,16 @@ #!/usr/bin/bash -echo "Simple: Test encryption for available certificate" +# source some functions +. common.sh + +test_header "Simple: Test encryption for available certificate" # There is an authenticated certificate for bob in the cert store -adduser --shell /bin/bash --disabled-password --gecos "" bob -echo "test mail" | sendmail bob@example.com +create_unix_user bob +send_test_mail bob@example.com -sleep 1 +RESULT_CODE=$(expect_mail bob encrypted) -if [ -f /var/mail/bob ] ; then - if grep -q "BEGIN PGP MESSAGE" /var/mail/bob ; then - RESULT_CODE=0 - else - echo "no encryption detected" - RESULT_CODE=1 - fi -else - echo "no mail detected" - RESULT_CODE=1 -fi - -deluser --remove-home bob +delete_unix_user bob exit $RESULT_CODE diff --git a/e2e-tests/tests/21_simple_not_encrypt.sh b/e2e-tests/tests/21_simple_not_encrypt.sh index ad38101..0af5a43 100644 --- a/e2e-tests/tests/21_simple_not_encrypt.sh +++ b/e2e-tests/tests/21_simple_not_encrypt.sh @@ -1,25 +1,16 @@ #!/usr/bin/bash -echo "Simple: Test encryption for unavailable certificate" +# source some functions +. common.sh + +test_header "Simple: Test encryption for unavailable certificate" # There is no authenticated certificate for alice in the cert store -adduser --shell /bin/bash --disabled-password --gecos "" alice -echo "test mail" | sendmail alice@example.com +create_unix_user alice +send_test_mail alice@example.com -sleep 1 +RESULT_CODE=$(expect_mail alice unencrypted) -if [ -f /var/mail/alice ] ; then - if grep -q "BEGIN PGP MESSAGE" /var/mail/alice ; then - echo "encryption detected - that is wrong" - RESULT_CODE=1 - else - RESULT_CODE=0 - fi -else - echo "no mail detected" - RESULT_CODE=1 -fi - -deluser --remove-home alice +delete_unix_user alice exit $RESULT_CODE diff --git a/e2e-tests/tests/30_fetch.sh b/e2e-tests/tests/30_fetch.sh index 85c797e..db6ed44 100644 --- a/e2e-tests/tests/30_fetch.sh +++ b/e2e-tests/tests/30_fetch.sh @@ -1,26 +1,17 @@ #!/usr/bin/bash -echo "Test encryption for certificate an a keyserver" +# source some functions +. common.sh + +test_header "Test encryption for certificate an a keyserver" # There is a certificate for carol on the keyserver # it's certified by an introducer -adduser --shell /bin/bash --disabled-password --gecos "" carol -echo "test mail" | sendmail carol@example.com +create_unix_user carol +send_test_mail carol@example.com -sleep 1 +RESULT_CODE=$(expect_mail carol encrypted) -if [ -f /var/mail/carol ] ; then - if grep -q "BEGIN PGP MESSAGE" /var/mail/carol ; then - RESULT_CODE=0 - else - echo "no encryption detected" - RESULT_CODE=1 - fi -else - echo "no mail detected" - RESULT_CODE=1 -fi - -deluser --remove-home carol +delete_unix_user carol exit $RESULT_CODE diff --git a/e2e-tests/tests/40_introducer_create.sh b/e2e-tests/tests/40_introducer_create.sh new file mode 100644 index 0000000..77234bf --- /dev/null +++ b/e2e-tests/tests/40_introducer_create.sh @@ -0,0 +1,41 @@ +#!/usr/bin/bash + +# source some functions +. common.sh + +test_header "Add introducer" + +ELLEN_FPR=$(sq key generate --shared-key --without-password --name "Ellen" --email "ellen@example.com" 2>&1 | grep "Fingerprint:" | cut -d ':' -f 2) + +cd $HUSK_DIR +$HUSK_BIN introducer add --cert $ELLEN_FPR --domains "example.org" --config config/config.toml +$HUSK_BIN introducer list --config config/config.toml + +create_unix_user fred +FRED_FPR=$(sq key generate --shared-key --without-password --name "Fred" --email "fred@example.org" 2>&1 | grep "Fingerprint:" | cut -d ':' -f 2) +sleep 1 +sq pki link retract --cert $FRED_FPR --all + +sq pki vouch add --certifier $ELLEN_FPR --cert $FRED_FPR --email "fred@example.org" + +send_test_mail fred@example.org + +RESULT_CODE=$(expect_mail fred encrypted) + +if [ "$RESULT_CODE" == "1" ] ; then + exit 1 +fi + +test_header "Remove introducer" + +$HUSK_BIN introducer remove --cert $ELLEN_FPR --config config/config.toml +$HUSK_BIN introducer list --config config/config.toml + +rm /var/mail/fred +send_test_mail fred@example.org + +RESULT_CODE=$(expect_mail fred unencrypted) + +delete_unix_user fred + +exit $RESULT_CODE diff --git a/e2e-tests/tests/41_introducer_load.sh b/e2e-tests/tests/41_introducer_load.sh new file mode 100644 index 0000000..8e4dabd --- /dev/null +++ b/e2e-tests/tests/41_introducer_load.sh @@ -0,0 +1,19 @@ +#!/usr/bin/bash + +# source some functions +. common.sh + +export SEQUOIA_HOME=$(mktemp -d) + +test_header "Import introducer from file" + +# create ellen +ELLEN_FPR=$(sq key generate --shared-key --without-password --name "Ellen" --email "ellen@example.com" 2>&1 | grep "Fingerprint:" | cut -d ':' -f 2) +sq cert export --cert $ELLEN_FPR > /tmp/ellen_pk.pgp + +cd $HUSK_DIR +$HUSK_BIN introducer add --cert-file /tmp/ellen_pk.pgp --domains example.org --config config/config.toml + +LIST=$($HUSK_BIN introducer list --config config/config.toml) + +echo $LIST | grep -q 'ellen@example.com' diff --git a/e2e-tests/tests/50_locals.sh b/e2e-tests/tests/50_locals.sh new file mode 100644 index 0000000..9364a5e --- /dev/null +++ b/e2e-tests/tests/50_locals.sh @@ -0,0 +1,11 @@ +#!/usr/bin/bash + +# source some functions +. common.sh + +test_header "List locals" + +GINA_FPR=$(sq key generate --shared-key --without-password --name "Gina" --email "gina@example.com" 2>&1 | grep "Fingerprint:" | cut -d ':' -f 2) + +cd $HUSK_DIR +$HUSK_BIN locals list --config config/config.toml | grep $GINA_FPR diff --git a/e2e-tests/tests/51_add_locals.sh b/e2e-tests/tests/51_add_locals.sh new file mode 100644 index 0000000..738f982 --- /dev/null +++ b/e2e-tests/tests/51_add_locals.sh @@ -0,0 +1,62 @@ +#!/usr/bin/bash + +# source some functions +. common.sh + +test_header "Add locals" + +sq key generate --shared-key --without-password --email 'hubert@example.com' --output /tmp/hubert.pgp --rev-cert /tmp/hubert_rev.pgp + +cd $HUSK_DIR + +$HUSK_BIN locals add --cert-file /tmp/hubert.pgp --config config/config.toml +if ! $HUSK_BIN locals list --config config/config.toml | grep -q "hubert@example.com" ; then + echo "adding failed" + exit 1 +fi + +# send a mail, husk should encrypt it +echo "send mail to hubert@example.com" +create_unix_user hubert +send_test_mail hubert@example.com + +if [ -f /var/mail/hubert ] ; then + if grep -q "BEGIN PGP MESSAGE" /var/mail/hubert ; then + RESULT_CODE=0 + else + echo "no encryption detected" + delete_unix_user hubert + exit 1 + fi + # remove mail + rm /var/mail/hubert +else + echo "no mail detected" + delete_unix_user hubert + exit 1 +fi + +sleep 1 +# remove hubert as local +HUBERT_FPR=$(sq cert list --cert-email hubert@example.com 2>/dev/null | head -n 1 | cut -d ' ' -f 3) +$HUSK_BIN locals remove --cert $HUBERT_FPR --config config/config.toml + +echo "send mail to hubert@example.com" +send_test_mail hubert@example.com + +if [ -f /var/mail/hubert ] ; then + if grep -q "BEGIN PGP MESSAGE" /var/mail/hubert ; then + echo "encryption detected where there should be none" + RESULT_CODE=1 + else + RESULT_CODE=0 + fi +else + echo "no mail detected" + RESULT_CODE=1 +fi + +delete_unix_user hubert + +exit $RESULT_CODE +