summaryrefslogtreecommitdiff
path: root/regress
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2012-12-11 22:42:12 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2012-12-11 22:42:12 +0000
commit6ef42482d1b34f4fa6debe6eff1b6b3c8cd5c786 (patch)
tree343da12483c12eae9dffc9b0d02664e8b19ebace /regress
parent998aaecf355d5f2ce88808553d67f3f1e7e927f6 (diff)
test the integrity of the packets; with djm@
Diffstat (limited to 'regress')
-rw-r--r--regress/usr.bin/ssh/Makefile9
-rw-r--r--regress/usr.bin/ssh/integrity.sh58
-rwxr-xr-xregress/usr.bin/ssh/modpipe.c122
3 files changed, 187 insertions, 2 deletions
diff --git a/regress/usr.bin/ssh/Makefile b/regress/usr.bin/ssh/Makefile
index 1f5b14536f9..a502cd3d3bd 100644
--- a/regress/usr.bin/ssh/Makefile
+++ b/regress/usr.bin/ssh/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.60 2012/12/02 20:47:48 djm Exp $
+# $OpenBSD: Makefile,v 1.61 2012/12/11 22:42:11 markus Exp $
REGRESS_TARGETS= t1 t2 t3 t4 t5 t6 t7 t8 t9
@@ -52,7 +52,8 @@ LTESTS= connect \
cert-userkey \
host-expand \
keys-command \
- forward-control
+ forward-control \
+ integrity
INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
#INTEROP_TESTS+=ssh-com ssh-com-client ssh-com-keygen ssh-com-sftp
@@ -126,6 +127,10 @@ t9: t9.out
ssh-keygen -lf t9.out > /dev/null
ssh-keygen -Bf t9.out > /dev/null
+modpipe: modpipe.c
+
+t-integrity: modpipe
+
.for t in ${LTESTS} ${INTEROP_TESTS}
t-${t}:
env SUDO="${SUDO}" ${TEST_ENV} \
diff --git a/regress/usr.bin/ssh/integrity.sh b/regress/usr.bin/ssh/integrity.sh
new file mode 100644
index 00000000000..23135685cef
--- /dev/null
+++ b/regress/usr.bin/ssh/integrity.sh
@@ -0,0 +1,58 @@
+# $OpenBSD: integrity.sh,v 1.1 2012/12/11 22:42:11 markus Exp $
+# Placed in the Public Domain.
+
+tid="integrity"
+
+# start at byte 2300 (i.e. after kex) and corrupt at different offsets
+# XXX the test hangs if we modify the low bytes of the packet length
+# XXX and ssh tries to read...
+tries=10
+startoffset=2300
+macs="hmac-sha1 hmac-md5 umac-64@openssh.com umac-128@openssh.com
+ hmac-sha1-96 hmac-md5-96 hmac-sha2-256 hmac-sha2-512
+ hmac-sha1-etm@openssh.com hmac-md5-etm@openssh.com
+ umac-64-etm@openssh.com umac-128-etm@openssh.com
+ hmac-sha1-96-etm@openssh.com hmac-md5-96-etm@openssh.com
+ hmac-sha2-256-etm@openssh.com hmac-sha2-512-etm@openssh.com"
+
+# sshd-command for proxy (see test-exec.sh)
+cmd="sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSH_LOGFILE} -i -f $OBJ/sshd_proxy"
+
+for m in $macs; do
+ trace "test $tid: mac $m"
+ elen=0
+ epad=0
+ emac=0
+ ecnt=0
+ skip=0
+ for off in $(jot $tries $startoffset); do
+ if [ $((skip--)) -gt 0 ]; then
+ # avoid modifying the high bytes of the length
+ continue
+ fi
+ # modify output from sshd at offset $off
+ pxy="proxycommand=$cmd | $OBJ/modpipe -m xor:$off:1"
+ output=$(${SSH} -m $m -2F $OBJ/ssh_proxy -o "$pxy" \
+ 999.999.999.999 true 2>&1)
+ if [ $? -eq 0 ]; then
+ fail "ssh -m $m succeeds with bit-flip at $off"
+ fi
+ ecnt=$((ecnt+1))
+ output=$(echo $output | tr -s '\r\n' '.')
+ verbose "test $tid: $m @$off $output"
+ case "$output" in
+ Bad?packet*) elen=$((elen+1)); skip=2;;
+ Corrupted?MAC*) emac=$((emac+1)); skip=0;;
+ padding*) epad=$((epad+1)); skip=0;;
+ *) fail "unexpected error mac $m at $off";;
+ esac
+ done
+ verbose "test $tid: $ecnt errors: mac $emac padding $epad length $elen"
+ if [ $emac -eq 0 ]; then
+ fail "$m: no mac errors"
+ fi
+ expect=$((ecnt-epad-elen))
+ if [ $emac -ne $expect ]; then
+ fail "$m: expected $expect mac errors, got $emac"
+ fi
+done
diff --git a/regress/usr.bin/ssh/modpipe.c b/regress/usr.bin/ssh/modpipe.c
new file mode 100755
index 00000000000..899e6ffb316
--- /dev/null
+++ b/regress/usr.bin/ssh/modpipe.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <err.h>
+#include <errno.h>
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: modpipe [-m modspec ...] < in > out\n");
+ fprintf(stderr, "modspec is one of:\n");
+ fprintf(stderr, " xor:offset:value - XOR \"value\" at \"offset\"\n");
+ fprintf(stderr, " andor:offset:val1:val2 - AND \"val1\" then OR \"val2\" at \"offset\"\n");
+ exit(1);
+}
+
+#define MAX_MODIFICATIONS 256
+struct modification {
+ enum { MOD_XOR, MOD_AND_OR } what;
+ u_int64_t offset;
+ u_int8_t m1, m2;
+};
+
+static void
+parse_modification(const char *s, struct modification *m)
+{
+ char what[16+1];
+ int n;
+
+ bzero(m, sizeof(*m));
+ if ((n = sscanf(s, "%16[^:]%*[:]%lli%*[:]%hhi%*[:]%hhi",
+ what, &m->offset, &m->m1, &m->m2)) < 3)
+ errx(1, "Invalid modification spec \"%s\"", s);
+ if (strcasecmp(what, "xor") == 0) {
+ m->what = MOD_XOR;
+ if (n > 3)
+ errx(1, "Invalid modification spec \"%s\"", s);
+ } else if (strcasecmp(what, "andor") == 0) {
+ m->what = MOD_AND_OR;
+ if (n != 4)
+ errx(1, "Invalid modification spec \"%s\"", s);
+ } else
+ errx(1, "Invalid modification type \"%s\"", what);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ u_char buf[8192];
+ size_t total;
+ ssize_t r, s, o;
+ struct modification mods[MAX_MODIFICATIONS];
+ u_int i, num_mods = 0;
+
+ while ((ch = getopt(argc, argv, "m:")) != -1) {
+ switch (ch) {
+ case 'm':
+ if (num_mods >= MAX_MODIFICATIONS)
+ errx(1, "Too many modifications");
+ parse_modification(optarg, &(mods[num_mods++]));
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ for (total = 0;;) {
+ r = s = read(STDIN_FILENO, buf, sizeof(buf));
+ if (r == 0)
+ return 0;
+ if (r < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ err(1, "read");
+ }
+ for (i = 0; i < num_mods; i++) {
+ if (mods[i].offset < total ||
+ mods[i].offset >= total + s)
+ continue;
+ switch (mods[i].what) {
+ case MOD_XOR:
+ buf[mods[i].offset - total] ^= mods[i].m1;
+ break;
+ case MOD_AND_OR:
+ buf[mods[i].offset - total] &= mods[i].m1;
+ buf[mods[i].offset - total] |= mods[i].m2;
+ break;
+ }
+ }
+ for (o = 0; o < s; o += r) {
+ r = write(STDOUT_FILENO, buf, s - o);
+ if (r == 0)
+ return 0;
+ if (r < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ err(1, "write");
+ }
+ }
+ total += s;
+ }
+ return 0;
+}