- (djm) [regress/unittests/Makefile]
   [regress/unittests/Makefile.inc]
   [regress/unittests/sshbuf/Makefile]
   [regress/unittests/sshbuf/test_sshbuf.c]
   [regress/unittests/sshbuf/test_sshbuf_fixed.c]
   [regress/unittests/sshbuf/test_sshbuf_fuzz.c]
   [regress/unittests/sshbuf/test_sshbuf_getput_basic.c]
   [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c]
   [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c]
   [regress/unittests/sshbuf/test_sshbuf_misc.c]
   [regress/unittests/sshbuf/tests.c]
   [regress/unittests/test_helper/Makefile]
   [regress/unittests/test_helper/fuzz.c]
   [regress/unittests/test_helper/test_helper.c]
   [regress/unittests/test_helper/test_helper.h]
   Import new unit tests from OpenBSD; not yet hooked up to build.
diff --git a/ChangeLog b/ChangeLog
index da8db6b..acf986b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -111,6 +111,22 @@
      was removed from malloc.c 10 days ago.
      
      OK from miod@
+ - (djm) [regress/unittests/Makefile]
+   [regress/unittests/Makefile.inc]
+   [regress/unittests/sshbuf/Makefile]
+   [regress/unittests/sshbuf/test_sshbuf.c]
+   [regress/unittests/sshbuf/test_sshbuf_fixed.c]
+   [regress/unittests/sshbuf/test_sshbuf_fuzz.c]
+   [regress/unittests/sshbuf/test_sshbuf_getput_basic.c]
+   [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c]
+   [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c]
+   [regress/unittests/sshbuf/test_sshbuf_misc.c]
+   [regress/unittests/sshbuf/tests.c]
+   [regress/unittests/test_helper/Makefile]
+   [regress/unittests/test_helper/fuzz.c]
+   [regress/unittests/test_helper/test_helper.c]
+   [regress/unittests/test_helper/test_helper.h]
+   Import new unit tests from OpenBSD; not yet hooked up to build.
 
 20140430
  - (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already
diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile
new file mode 100644
index 0000000..2581a58
--- /dev/null
+++ b/regress/unittests/Makefile
@@ -0,0 +1,5 @@
+#	$OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $
+
+SUBDIR=	test_helper sshbuf
+
+.include <bsd.subdir.mk>
diff --git a/regress/unittests/Makefile.inc b/regress/unittests/Makefile.inc
new file mode 100644
index 0000000..4c33637
--- /dev/null
+++ b/regress/unittests/Makefile.inc
@@ -0,0 +1,59 @@
+#	$OpenBSD: Makefile.inc,v 1.1 2014/04/30 05:32:00 djm Exp $
+
+.include <bsd.own.mk>
+.include <bsd.obj.mk>
+
+# enable warnings
+WARNINGS=Yes
+
+DEBUG=-g
+CFLAGS+=	-fstack-protector-all
+CDIAGFLAGS=	-Wall
+CDIAGFLAGS+=	-Wextra
+CDIAGFLAGS+=	-Werror
+CDIAGFLAGS+=	-Wchar-subscripts
+CDIAGFLAGS+=	-Wcomment
+CDIAGFLAGS+=	-Wformat
+CDIAGFLAGS+=	-Wformat-security
+CDIAGFLAGS+=	-Wimplicit
+CDIAGFLAGS+=	-Winline
+CDIAGFLAGS+=	-Wmissing-declarations
+CDIAGFLAGS+=	-Wmissing-prototypes
+CDIAGFLAGS+=	-Wparentheses
+CDIAGFLAGS+=	-Wpointer-arith
+CDIAGFLAGS+=	-Wpointer-sign
+CDIAGFLAGS+=	-Wreturn-type
+CDIAGFLAGS+=	-Wshadow
+CDIAGFLAGS+=	-Wsign-compare
+CDIAGFLAGS+=	-Wstrict-aliasing
+CDIAGFLAGS+=	-Wstrict-prototypes
+CDIAGFLAGS+=	-Wswitch
+CDIAGFLAGS+=	-Wtrigraphs
+CDIAGFLAGS+=	-Wuninitialized
+CDIAGFLAGS+=	-Wunused
+.if ${COMPILER_VERSION} == "gcc4"
+CDIAGFLAGS+=	-Wold-style-definition
+.endif
+
+SSHREL=../../../../../usr.bin/ssh
+
+CFLAGS+=-I${.CURDIR}/../test_helper -I${.CURDIR}/${SSHREL}
+
+.if exists(${.CURDIR}/../test_helper/${__objdir})
+LDADD+=-L${.CURDIR}/../test_helper/${__objdir} -ltest_helper
+DPADD+=${.CURDIR}/../test_helper/${__objdir}/libtest_helper.a
+.else
+LDADD+=-L${.CURDIR}/../test_helper -ltest_helper
+DPADD+=${.CURDIR}/../test_helper/libtest_helper.a
+.endif
+
+.if exists(${.CURDIR}/${SSHREL}/lib/${__objdir})
+LDADD+=-L${.CURDIR}/${SSHREL}/lib/${__objdir} -lssh
+DPADD+=${.CURDIR}/${SSHREL}/lib/${__objdir}/libssh.a
+.else
+LDADD+=-L${.CURDIR}/${SSHREL}/lib -lssh
+DPADD+=${.CURDIR}/${SSHREL}/lib/libssh.a
+.endif
+
+LDADD+= -lcrypto
+DPADD+= ${LIBCRYPTO}
diff --git a/regress/unittests/sshbuf/Makefile b/regress/unittests/sshbuf/Makefile
new file mode 100644
index 0000000..85f99ac
--- /dev/null
+++ b/regress/unittests/sshbuf/Makefile
@@ -0,0 +1,14 @@
+#	$OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $
+
+PROG=test_sshbuf
+SRCS=tests.c
+SRCS+=test_sshbuf.c
+SRCS+=test_sshbuf_getput_basic.c
+SRCS+=test_sshbuf_getput_crypto.c
+SRCS+=test_sshbuf_misc.c
+SRCS+=test_sshbuf_fuzz.c
+SRCS+=test_sshbuf_getput_fuzz.c
+SRCS+=test_sshbuf_fixed.c
+
+.include <bsd.regress.mk>
+
diff --git a/regress/unittests/sshbuf/test_sshbuf.c b/regress/unittests/sshbuf/test_sshbuf.c
new file mode 100644
index 0000000..834dcd0
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf.c
@@ -0,0 +1,236 @@
+/* 	$OpenBSD: test_sshbuf.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_helper.h"
+
+#include "ssherr.h"
+#define SSHBUF_INTERNAL 1	/* access internals for testing */
+#include "sshbuf.h"
+
+void sshbuf_tests(void);
+
+void
+sshbuf_tests(void)
+{
+	struct sshbuf *p1;
+	const u_char *cdp;
+	u_char *dp;
+	size_t sz;
+	int r;
+
+	TEST_START("allocate sshbuf");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	TEST_DONE();
+
+	TEST_START("max size on fresh buffer");
+	ASSERT_SIZE_T_GT(sshbuf_max_size(p1), 0);
+	TEST_DONE();
+
+	TEST_START("available on fresh buffer");
+	ASSERT_SIZE_T_GT(sshbuf_avail(p1), 0);
+	TEST_DONE();
+
+	TEST_START("len = 0 on empty buffer");
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	TEST_DONE();
+
+	TEST_START("set valid max size");
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 65536), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 65536);
+	TEST_DONE();
+
+	TEST_START("available on limited buffer");
+	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 65536);
+	TEST_DONE();
+
+	TEST_START("free");
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("consume on empty buffer");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
+	ASSERT_INT_EQ(sshbuf_consume(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("consume_end on empty buffer");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_consume_end(p1, 0), 0);
+	ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("reserve space");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	r = sshbuf_reserve(p1, 1, &dp);
+	ASSERT_INT_EQ(r, 0);
+	ASSERT_PTR_NE(dp, NULL);
+	*dp = 0x11;
+	r = sshbuf_reserve(p1, 3, &dp);
+	ASSERT_INT_EQ(r, 0);
+	ASSERT_PTR_NE(dp, NULL);
+	*dp++ = 0x22;
+	*dp++ = 0x33;
+	*dp++ = 0x44;
+	TEST_DONE();
+
+	TEST_START("sshbuf_len on filled buffer");
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	TEST_DONE();
+
+	TEST_START("sshbuf_ptr on filled buffer");
+	cdp = sshbuf_ptr(p1);
+	ASSERT_PTR_NE(cdp, NULL);
+	ASSERT_U8_EQ(cdp[0], 0x11);
+	ASSERT_U8_EQ(cdp[1], 0x22);
+	ASSERT_U8_EQ(cdp[2], 0x33);
+	ASSERT_U8_EQ(cdp[3], 0x44);
+	TEST_DONE();
+
+	TEST_START("consume on filled buffer");
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	r = sshbuf_consume(p1, 64);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 3);
+	cdp = sshbuf_ptr(p1);
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_U8_EQ(cdp[0], 0x22);
+	ASSERT_INT_EQ(sshbuf_consume(p1, 2), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	cdp = sshbuf_ptr(p1);
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_U8_EQ(cdp[0], 0x44);
+	r = sshbuf_consume(p1, 2);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	r = sshbuf_consume(p1, 1);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("consume_end on filled buffer");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	r = sshbuf_reserve(p1, 4, &dp);
+	ASSERT_INT_EQ(r, 0);
+	ASSERT_PTR_NE(dp, NULL);
+	*dp++ = 0x11;
+	*dp++ = 0x22;
+	*dp++ = 0x33;
+	*dp++ = 0x44;
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	r = sshbuf_consume_end(p1, 5);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	ASSERT_INT_EQ(sshbuf_consume_end(p1, 3), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	cdp = sshbuf_ptr(p1);
+	ASSERT_PTR_NE(cdp, NULL);
+	ASSERT_U8_EQ(*cdp, 0x11);
+	r = sshbuf_consume_end(p1, 2);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("fill limited buffer");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
+	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
+	r = sshbuf_reserve(p1, 1223, &dp);
+	ASSERT_INT_EQ(r, 0);
+	ASSERT_PTR_NE(dp, NULL);
+	memset(dp, 0xd7, 1223);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
+	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 0);
+	r = sshbuf_reserve(p1, 1, &dp);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_PTR_EQ(dp, NULL);
+	TEST_DONE();
+
+	TEST_START("consume and force compaction");
+	ASSERT_INT_EQ(sshbuf_consume(p1, 223), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
+	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
+	r = sshbuf_reserve(p1, 224, &dp);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_PTR_EQ(dp, NULL);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
+	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
+	r = sshbuf_reserve(p1, 223, &dp);
+	ASSERT_INT_EQ(r, 0);
+	ASSERT_PTR_NE(dp, NULL);
+	memset(dp, 0x7d, 223);
+	cdp = sshbuf_ptr(p1);
+	ASSERT_PTR_NE(cdp, NULL);
+	ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
+	ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
+	TEST_DONE();
+
+	TEST_START("resize full buffer");
+	r = sshbuf_set_max_size(p1, 1000);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	sz = roundup(1223 + SSHBUF_SIZE_INC * 3, SSHBUF_SIZE_INC);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sz), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
+	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - 1223);
+	ASSERT_INT_EQ(sshbuf_len(p1), 1223);
+	TEST_DONE();
+
+	/* NB. uses sshbuf internals */
+	TEST_START("alloc chunking");
+	r = sshbuf_reserve(p1, 1, &dp);
+	ASSERT_INT_EQ(r, 0);
+	ASSERT_PTR_NE(dp, NULL);
+	*dp = 0xff;
+	cdp = sshbuf_ptr(p1);
+	ASSERT_PTR_NE(cdp, NULL);
+	ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
+	ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
+	ASSERT_MEM_FILLED_EQ(cdp + 1223, 0xff, 1);
+	ASSERT_SIZE_T_EQ(sshbuf_alloc(p1) % SSHBUF_SIZE_INC, 0);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("reset buffer");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
+	r = sshbuf_reserve(p1, 1223, &dp);
+	ASSERT_INT_EQ(r, 0);
+	ASSERT_PTR_NE(dp, NULL);
+	memset(dp, 0xd7, 1223);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
+	sshbuf_reset(p1);
+	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
+	sshbuf_free(p1);
+	TEST_DONE();
+}
diff --git a/regress/unittests/sshbuf/test_sshbuf_fixed.c b/regress/unittests/sshbuf/test_sshbuf_fixed.c
new file mode 100644
index 0000000..62c815a
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_fixed.c
@@ -0,0 +1,122 @@
+/* 	$OpenBSD: test_sshbuf_fixed.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_helper.h"
+
+#define SSHBUF_INTERNAL 1  /* access internals for testing */
+#include "sshbuf.h"
+#include "ssherr.h"
+
+void sshbuf_fixed(void);
+
+const u_char test_buf[] = "\x01\x12\x34\x56\x78\x00\x00\x00\x05hello";
+
+void
+sshbuf_fixed(void)
+{
+	struct sshbuf *p1, *p2, *p3;
+	u_char c;
+	char *s;
+	u_int i;
+	size_t l;
+
+	TEST_START("sshbuf_from");
+	p1 = sshbuf_from(test_buf, sizeof(test_buf));
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_PTR_EQ(sshbuf_mutable_ptr(p1), NULL);
+	ASSERT_INT_EQ(sshbuf_check_reserve(p1, 1), SSH_ERR_BUFFER_READ_ONLY);
+	ASSERT_INT_EQ(sshbuf_reserve(p1, 1, NULL), SSH_ERR_BUFFER_READ_ONLY);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 200), SSH_ERR_BUFFER_READ_ONLY);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), SSH_ERR_BUFFER_READ_ONLY);
+	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 0);
+	ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_from data");
+	p1 = sshbuf_from(test_buf, sizeof(test_buf) - 1);
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf);
+	ASSERT_INT_EQ(sshbuf_get_u8(p1, &c), 0);
+	ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf + 1);
+	ASSERT_U8_EQ(c, 1);
+	ASSERT_INT_EQ(sshbuf_get_u32(p1, &i), 0);
+	ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf + 5);
+	ASSERT_U32_EQ(i, 0x12345678);
+	ASSERT_INT_EQ(sshbuf_get_cstring(p1, &s, &l), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	ASSERT_STRING_EQ(s, "hello");
+	ASSERT_SIZE_T_EQ(l, 5);
+	sshbuf_free(p1);
+	free(s);
+	TEST_DONE();
+
+	TEST_START("sshbuf_fromb ");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_U_INT_EQ(sshbuf_refcount(p1), 1);
+	ASSERT_PTR_EQ(sshbuf_parent(p1), NULL);
+	ASSERT_INT_EQ(sshbuf_put(p1, test_buf, sizeof(test_buf) - 1), 0);
+	p2 = sshbuf_fromb(p1);
+	ASSERT_PTR_NE(p2, NULL);
+	ASSERT_U_INT_EQ(sshbuf_refcount(p1), 2);
+	ASSERT_PTR_EQ(sshbuf_parent(p1), NULL);
+	ASSERT_PTR_EQ(sshbuf_parent(p2), p1);
+	ASSERT_PTR_EQ(sshbuf_ptr(p2), sshbuf_ptr(p1));
+	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+	ASSERT_PTR_NE(sshbuf_ptr(p2), NULL);
+	ASSERT_PTR_EQ(sshbuf_mutable_ptr(p1), NULL);
+	ASSERT_PTR_EQ(sshbuf_mutable_ptr(p2), NULL);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sshbuf_len(p2));
+	ASSERT_INT_EQ(sshbuf_get_u8(p2, &c), 0);
+	ASSERT_PTR_EQ(sshbuf_ptr(p2), sshbuf_ptr(p1) + 1);
+	ASSERT_U8_EQ(c, 1);
+	ASSERT_INT_EQ(sshbuf_get_u32(p2, &i), 0);
+	ASSERT_PTR_EQ(sshbuf_ptr(p2), sshbuf_ptr(p1) + 5);
+	ASSERT_U32_EQ(i, 0x12345678);
+	ASSERT_INT_EQ(sshbuf_get_cstring(p2, &s, &l), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p2), 0);
+	ASSERT_STRING_EQ(s, "hello");
+	ASSERT_SIZE_T_EQ(l, 5);
+	sshbuf_free(p1);
+	ASSERT_U_INT_EQ(sshbuf_refcount(p1), 1);
+	sshbuf_free(p2);
+	free(s);
+	TEST_DONE();
+
+	TEST_START("sshbuf_froms");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x01), 0);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0);
+	ASSERT_INT_EQ(sshbuf_put_cstring(p1, "hello"), 0);
+	p2 = sshbuf_new();
+	ASSERT_PTR_NE(p2, NULL);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(test_buf) - 1);
+	ASSERT_INT_EQ(sshbuf_put_stringb(p2, p1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p2), sizeof(test_buf) + 4 - 1);
+	ASSERT_INT_EQ(sshbuf_froms(p2, &p3), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p2), 0);
+	ASSERT_PTR_NE(p3, NULL);
+	ASSERT_PTR_NE(sshbuf_ptr(p3), NULL);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p3), sizeof(test_buf) - 1);
+	ASSERT_MEM_EQ(sshbuf_ptr(p3), test_buf, sizeof(test_buf) - 1);
+	sshbuf_free(p3);
+	ASSERT_INT_EQ(sshbuf_put_stringb(p2, p1), 0);
+	ASSERT_INT_EQ(sshbuf_consume_end(p2, 1), 0);
+	ASSERT_INT_EQ(sshbuf_froms(p2, &p3), SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_PTR_EQ(p3, NULL);
+	sshbuf_free(p2);
+	sshbuf_free(p1);
+}
diff --git a/regress/unittests/sshbuf/test_sshbuf_fuzz.c b/regress/unittests/sshbuf/test_sshbuf_fuzz.c
new file mode 100644
index 0000000..a014b04
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_fuzz.c
@@ -0,0 +1,123 @@
+/* 	$OpenBSD: test_sshbuf_fuzz.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_helper.h"
+
+#include "ssherr.h"
+#include "sshbuf.h"
+
+#define NUM_FUZZ_TESTS (1 << 18)
+
+void sshbuf_fuzz_tests(void);
+
+void
+sshbuf_fuzz_tests(void)
+{
+	struct sshbuf *p1;
+	u_char *dp;
+	size_t sz, sz2, i;
+	u_int32_t r;
+	int ret;
+
+	/* NB. uses sshbuf internals */
+	TEST_START("fuzz alloc/dealloc");
+	p1 = sshbuf_new();
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0);
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
+	for (i = 0; i < NUM_FUZZ_TESTS; i++) {
+		r = arc4random_uniform(10);
+		if (r == 0) {
+			/* 10% chance: small reserve */
+			r = arc4random_uniform(10);
+ fuzz_reserve:
+			sz = sshbuf_avail(p1);
+			sz2 = sshbuf_len(p1);
+			ret = sshbuf_reserve(p1, r, &dp);
+			if (ret < 0) {
+				ASSERT_PTR_EQ(dp, NULL);
+				ASSERT_SIZE_T_LT(sz, r);
+				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
+				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
+			} else {
+				ASSERT_PTR_NE(dp, NULL);
+				ASSERT_SIZE_T_GE(sz, r);
+				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - r);
+				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 + r);
+				memset(dp, arc4random_uniform(255) + 1, r);
+			}
+		} else if (r < 3) {
+			/* 20% chance: big reserve */
+			r = arc4random_uniform(8 * 1024);
+			goto fuzz_reserve;
+		} else if (r == 3) {
+			/* 10% chance: small consume */
+			r = arc4random_uniform(10);
+ fuzz_consume:
+			sz = sshbuf_avail(p1);
+			sz2 = sshbuf_len(p1);
+			/* 50% change consume from end, otherwise start */
+			ret = ((arc4random() & 1) ?
+			    sshbuf_consume : sshbuf_consume_end)(p1, r);
+			if (ret < 0) {
+				ASSERT_SIZE_T_LT(sz2, r);
+				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
+				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
+			} else {
+				ASSERT_SIZE_T_GE(sz2, r);
+				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz + r);
+				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 - r);
+			}
+		} else if (r < 8) {
+			/* 40% chance: big consume */
+			r = arc4random_uniform(2 * 1024);
+			goto fuzz_consume;
+		} else if (r == 8) {
+			/* 10% chance: reset max size */
+			r = arc4random_uniform(16 * 1024);
+			sz = sshbuf_max_size(p1);
+			if (sshbuf_set_max_size(p1, r) < 0)
+				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
+			else
+				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), r);
+		} else {
+			if (arc4random_uniform(8192) == 0) {
+				/* tiny chance: new buffer */
+				ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+				ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
+				sshbuf_free(p1);
+				p1 = sshbuf_new();
+				ASSERT_PTR_NE(p1, NULL);
+				ASSERT_INT_EQ(sshbuf_set_max_size(p1,
+				    16 * 1024), 0);
+			} else {
+				/* Almost 10%: giant reserve */
+				/* use arc4random_buf for r > 2^32 on 64 bit */
+				arc4random_buf(&r, sizeof(r));
+				while (r < SSHBUF_SIZE_MAX / 2) {
+					r <<= 1;
+					r |= arc4random() & 1;
+				}
+				goto fuzz_reserve;
+			}
+		}
+		ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+		ASSERT_SIZE_T_LE(sshbuf_max_size(p1), 16 * 1024);
+	}
+	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
+	sshbuf_free(p1);
+	TEST_DONE();
+}
diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_basic.c b/regress/unittests/sshbuf/test_sshbuf_getput_basic.c
new file mode 100644
index 0000000..2d469ec
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_getput_basic.c
@@ -0,0 +1,480 @@
+/* 	$OpenBSD: test_sshbuf_getput_basic.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_helper.h"
+#include "ssherr.h"
+#include "sshbuf.h"
+
+void sshbuf_getput_basic_tests(void);
+
+void
+sshbuf_getput_basic_tests(void)
+{
+	struct sshbuf *p1, *p2;
+	const u_char *cd;
+	u_char *d, d2[32], x[] = {
+		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x00, 0x99
+	};
+	u_int64_t v64;
+	u_int32_t v32;
+	u_int16_t v16;
+	u_char v8;
+	size_t s;
+	char *s2;
+	int r;
+	u_char bn1[] = { 0x00, 0x00, 0x00 };
+	u_char bn2[] = { 0x00, 0x00, 0x01, 0x02 };
+	u_char bn3[] = { 0x00, 0x80, 0x09 };
+	u_char bn_exp1[] = { 0x00, 0x00, 0x00, 0x00 };
+	u_char bn_exp2[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 0x02 };
+	u_char bn_exp3[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x80, 0x09 };
+
+	TEST_START("PEEK_U64");
+	ASSERT_U64_EQ(PEEK_U64(x), 0x1122334455667788ULL);
+	TEST_DONE();
+
+	TEST_START("PEEK_U32");
+	ASSERT_U32_EQ(PEEK_U32(x), 0x11223344);
+	TEST_DONE();
+
+	TEST_START("PEEK_U16");
+	ASSERT_U16_EQ(PEEK_U16(x), 0x1122);
+	TEST_DONE();
+
+	TEST_START("POKE_U64");
+	bzero(d2, sizeof(d2));
+	POKE_U64(d2, 0x1122334455667788ULL);
+	ASSERT_MEM_EQ(d2, x, 8);
+	TEST_DONE();
+	
+	TEST_START("POKE_U32");
+	bzero(d2, sizeof(d2));
+	POKE_U32(d2, 0x11223344);
+	ASSERT_MEM_EQ(d2, x, 4);
+	TEST_DONE();
+	
+	TEST_START("POKE_U16");
+	bzero(d2, sizeof(d2));
+	POKE_U16(d2, 0x1122);
+	ASSERT_MEM_EQ(d2, x, 2);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, 5), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 5);
+	cd = sshbuf_ptr(p1);
+	ASSERT_PTR_NE(cd, NULL);
+	ASSERT_U8_EQ(cd[0], 0x11);
+	ASSERT_U8_EQ(cd[1], 0x22);
+	ASSERT_U8_EQ(cd[2], 0x33);
+	ASSERT_U8_EQ(cd[3], 0x44);
+	ASSERT_U8_EQ(cd[4], 0x55);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get");
+	ASSERT_INT_EQ(sshbuf_get(p1, d2, 4), 0);
+	ASSERT_MEM_EQ(d2, x, 4);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	ASSERT_U8_EQ(*(sshbuf_ptr(p1)), 0x55);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get truncated");
+	r = sshbuf_get(p1, d2, 4);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	ASSERT_U8_EQ(*(sshbuf_ptr(p1)), 0x55);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put truncated");
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 4), 0);
+	r = sshbuf_put(p1, x, 5);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_u64");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, 10), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 10);
+	ASSERT_INT_EQ(sshbuf_get_u64(p1, &v64), 0);
+	ASSERT_U64_EQ(v64, 0x1122334455667788ULL);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_u64 truncated");
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	r = sshbuf_get_u64(p1, &v64);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_u32");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, 10), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 10);
+	ASSERT_INT_EQ(sshbuf_get_u32(p1, &v32), 0);
+	ASSERT_U32_EQ(v32, 0x11223344);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 6);
+	ASSERT_INT_EQ(sshbuf_get_u32(p1, &v32), 0);
+	ASSERT_U32_EQ(v32, 0x55667788);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_u32 truncated");
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	r = sshbuf_get_u32(p1, &v32);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_u16");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, 9), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 9);
+	ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
+	ASSERT_U16_EQ(v16, 0x1122);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 7);
+	ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
+	ASSERT_U16_EQ(v16, 0x3344);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 5);
+	ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
+	ASSERT_U16_EQ(v16, 0x5566);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 3);
+	ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
+	ASSERT_U16_EQ(v16, 0x7788);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_u16 truncated");
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	r = sshbuf_get_u16(p1, &v16);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_u8");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, 2), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	ASSERT_INT_EQ(sshbuf_get_u8(p1, &v8), 0);
+	ASSERT_U8_EQ(v8, 0x11);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	ASSERT_INT_EQ(sshbuf_get_u8(p1, &v8), 0);
+	ASSERT_U8_EQ(v8, 0x22);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_u8 truncated");
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	r = sshbuf_get_u8(p1, &v8);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_u64");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u64(p1, 0x1122334455667788ULL), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 8);
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 8);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_u64 exact");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 8), 0);
+	ASSERT_INT_EQ(sshbuf_put_u64(p1, 0x1122334455667788ULL), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 8);
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 8);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_u64 limited");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 7), 0);
+	r = sshbuf_put_u64(p1, 0x1122334455667788ULL);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	sshbuf_free(p1);
+	TEST_DONE();
+	
+	TEST_START("sshbuf_put_u32");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x11223344), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 4);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_u32 exact");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 4), 0);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x11223344), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 4);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_u32 limited");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 3), 0);
+	r = sshbuf_put_u32(p1, 0x11223344);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	sshbuf_free(p1);
+	TEST_DONE();
+	
+	TEST_START("sshbuf_put_u16");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0x1122), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_u16");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 2), 0);
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0x1122), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_u16 limited");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1), 0);
+	r = sshbuf_put_u16(p1, 0x1122);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_string");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4 + 4);
+	ASSERT_INT_EQ(sshbuf_get_string(p1, &d, &s), 0);
+	ASSERT_SIZE_T_EQ(s, sizeof(x));
+	ASSERT_MEM_EQ(d, x, sizeof(x));
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	free(d);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_string exact");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(x) + 4), 0);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+	ASSERT_INT_EQ(sshbuf_get_string(p1, &d, &s), 0);
+	ASSERT_SIZE_T_EQ(s, sizeof(x));
+	ASSERT_MEM_EQ(d, x, sizeof(x));
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	free(d);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_string truncated");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+	ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 3);
+	r = sshbuf_get_string(p1, &d, &s);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 3);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_string giant");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0xffffffff), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+	r = sshbuf_get_string(p1, &d, &s);
+	ASSERT_INT_EQ(r, SSH_ERR_STRING_TOO_LARGE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_cstring giant");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0xffffffff), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+	r = sshbuf_get_cstring(p1, &s2, &s);
+	ASSERT_INT_EQ(r, SSH_ERR_STRING_TOO_LARGE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_cstring embedded \\0");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+	r = sshbuf_get_cstring(p1, &s2, NULL);
+	ASSERT_INT_EQ(r, SSH_ERR_INVALID_FORMAT);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_cstring trailing \\0");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x) - 1), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x) - 1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4 - 1);
+	ASSERT_INT_EQ(sshbuf_get_cstring(p1, &s2, &s), 0);
+	ASSERT_SIZE_T_EQ(s, sizeof(x) - 1);
+	ASSERT_MEM_EQ(s2, x, s);
+	free(s2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_string");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_string(p1, x, sizeof(x)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+	ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), sizeof(x));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1) + 4, x, sizeof(x));
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_string limited");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(x) + 4 - 1), 0);
+	r = sshbuf_put_string(p1, x, sizeof(x));
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_string giant");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	r = sshbuf_put_string(p1, (void *)0x01, 0xfffffffc);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_putf");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	r = sshbuf_putf(p1, "%s %d %x", "hello", 23, 0x5f);
+	ASSERT_INT_EQ(r, 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 11);
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), "hello 23 5f", 11);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_putb");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	p2 = sshbuf_new();
+	ASSERT_PTR_NE(p2, NULL);
+	ASSERT_INT_EQ(sshbuf_put(p1, "blahblahblah", 12), 0);
+	ASSERT_INT_EQ(sshbuf_putb(p2, p1), 0);
+	sshbuf_free(p1);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p2), 12);
+	ASSERT_MEM_EQ(sshbuf_ptr(p2), "blahblahblah", 12);
+	sshbuf_free(p2);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2_bytes empty buf");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, NULL, 0), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp1));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp1, sizeof(bn_exp1));
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2_bytes all zeroes");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn1, sizeof(bn1)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp1));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp1, sizeof(bn_exp1));
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2_bytes simple");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn2+2, sizeof(bn2)-2), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp2));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp2, sizeof(bn_exp2));
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2_bytes leading zero");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn2, sizeof(bn2)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp2));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp2, sizeof(bn_exp2));
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2_bytes neg");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn3+1, sizeof(bn3)-1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp3));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp3, sizeof(bn_exp3));
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2_bytes neg and leading zero");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn3, sizeof(bn3)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp3));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp3, sizeof(bn_exp3));
+	sshbuf_free(p1);
+	TEST_DONE();
+}
diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c
new file mode 100644
index 0000000..d7d4dc3
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c
@@ -0,0 +1,398 @@
+/* 	$OpenBSD: test_sshbuf_getput_crypto.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/objects.h>
+
+#include "test_helper.h"
+#include "ssherr.h"
+#include "sshbuf.h"
+
+void sshbuf_getput_crypto_tests(void);
+
+void
+sshbuf_getput_crypto_tests(void)
+{
+	struct sshbuf *p1;
+	const u_char *d;
+	size_t s;
+	BIGNUM *bn, *bn2, *bn_x, *bn_y;
+	/* This one has num_bits != num_bytes * 8 to test bignum1 encoding */
+	const char *hexbn1 = "0102030405060708090a0b0c0d0e0f10";
+	/* This one has MSB set to test bignum2 encoding negative-avoidance */
+	const char *hexbn2 = "f0e0d0c0b0a0908070605040302010007fff11";
+	u_char expbn1[] = {
+		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+	};
+	u_char expbn2[] = {
+		0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80,
+		0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00,
+		0x7f, 0xff, 0x11
+	};
+	int ec256_nid = NID_X9_62_prime256v1;
+	char *ec256_x = "0C828004839D0106AA59575216191357"
+		        "34B451459DADB586677EF9DF55784999";
+	char *ec256_y = "4D196B50F0B4E94B3C73E3A9D4CD9DF2"
+	                "C8F9A35E42BDD047550F69D80EC23CD4";
+	u_char expec256[] = {
+		0x04,
+		0x0c, 0x82, 0x80, 0x04, 0x83, 0x9d, 0x01, 0x06,
+		0xaa, 0x59, 0x57, 0x52, 0x16, 0x19, 0x13, 0x57,
+		0x34, 0xb4, 0x51, 0x45, 0x9d, 0xad, 0xb5, 0x86,
+		0x67, 0x7e, 0xf9, 0xdf, 0x55, 0x78, 0x49, 0x99,
+		0x4d, 0x19, 0x6b, 0x50, 0xf0, 0xb4, 0xe9, 0x4b,
+		0x3c, 0x73, 0xe3, 0xa9, 0xd4, 0xcd, 0x9d, 0xf2,
+		0xc8, 0xf9, 0xa3, 0x5e, 0x42, 0xbd, 0xd0, 0x47,
+		0x55, 0x0f, 0x69, 0xd8, 0x0e, 0xc2, 0x3c, 0xd4
+	};
+	EC_KEY *eck;
+	EC_POINT *ecp;
+	int r;
+
+#define MKBN(b, bnn) \
+	do { \
+		bnn = NULL; \
+		ASSERT_INT_GT(BN_hex2bn(&bnn, b), 0); \
+	} while (0)
+
+	TEST_START("sshbuf_put_bignum1");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 2);
+	ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn1, sizeof(expbn1));
+	BN_free(bn);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum1 limited");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0);
+	r = sshbuf_put_bignum1(p1, bn);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	BN_free(bn);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum1 bn2");
+	MKBN(hexbn2, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 2);
+	ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn2, sizeof(expbn2));
+	BN_free(bn);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum1 bn2 limited");
+	MKBN(hexbn2, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0);
+	r = sshbuf_put_bignum1(p1, bn);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	BN_free(bn);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 4);
+	ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn));
+	ASSERT_MEM_EQ(sshbuf_ptr(p1) + 4, expbn1, sizeof(expbn1));
+	BN_free(bn);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2 limited");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 3), 0);
+	r = sshbuf_put_bignum2(p1, bn);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	BN_free(bn);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2 bn2");
+	MKBN(hexbn2, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4 + 1); /* MSB */
+	ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn) + 1);
+	ASSERT_U8_EQ(*(sshbuf_ptr(p1) + 4), 0x00);
+	ASSERT_MEM_EQ(sshbuf_ptr(p1) + 5, expbn2, sizeof(expbn2));
+	BN_free(bn);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_bignum2 bn2 limited");
+	MKBN(hexbn2, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn2) + 3), 0);
+	r = sshbuf_put_bignum2(p1, bn);
+	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+	BN_free(bn);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum1");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1));
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
+	bn2 = BN_new();
+	ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0);
+	ASSERT_BIGNUM_EQ(bn, bn2);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum1 truncated");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1);
+	bn2 = BN_new();
+	r = sshbuf_get_bignum1(p1, bn2);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum1 giant");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xffff), 0);
+	ASSERT_INT_EQ(sshbuf_reserve(p1, (0xffff + 7) / 8, NULL), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8));
+	bn2 = BN_new();
+	r = sshbuf_get_bignum1(p1, bn2);
+	ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8));
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum1 bn2");
+	MKBN(hexbn2, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2));
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
+	bn2 = BN_new();
+	ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0);
+	ASSERT_BIGNUM_EQ(bn, bn2);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum1 bn2 truncated");
+	MKBN(hexbn2, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1);
+	bn2 = BN_new();
+	r = sshbuf_get_bignum1(p1, bn2);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum2");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + sizeof(expbn1));
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
+	bn2 = BN_new();
+	ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0);
+	ASSERT_BIGNUM_EQ(bn, bn2);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum2 truncated");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0);
+	bn2 = BN_new();
+	r = sshbuf_get_bignum2(p1, bn2);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 3);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum2 giant");
+	MKBN(hexbn1, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, 65536), 0);
+	ASSERT_INT_EQ(sshbuf_reserve(p1, 65536, NULL), 0);
+	bn2 = BN_new();
+	r = sshbuf_get_bignum2(p1, bn2);
+	ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 65536 + 4);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum2 bn2");
+	MKBN(hexbn2, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0); /* MSB */
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + 1 + sizeof(expbn2));
+	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
+	bn2 = BN_new();
+	ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0);
+	ASSERT_BIGNUM_EQ(bn, bn2);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum2 bn2 truncated");
+	MKBN(hexbn2, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0);
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0);
+	bn2 = BN_new();
+	r = sshbuf_get_bignum2(p1, bn2);
+	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 1 + 4 - 1);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_bignum2 bn2 negative");
+	MKBN(hexbn2, bn);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0);
+	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0);
+	bn2 = BN_new();
+	r = sshbuf_get_bignum2(p1, bn2);
+	ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_IS_NEGATIVE);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4);
+	BN_free(bn);
+	BN_free(bn2);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_put_ec");
+	eck = EC_KEY_new_by_curve_name(ec256_nid);
+	ASSERT_PTR_NE(eck, NULL);
+	ecp = EC_POINT_new(EC_KEY_get0_group(eck));
+	ASSERT_PTR_NE(ecp, NULL);
+	MKBN(ec256_x, bn_x);
+	MKBN(ec256_y, bn_y);
+	ASSERT_INT_EQ(EC_POINT_set_affine_coordinates_GFp(
+	    EC_KEY_get0_group(eck), ecp, bn_x, bn_y, NULL), 1);
+	ASSERT_INT_EQ(EC_KEY_set_public_key(eck, ecp), 1);
+	BN_free(bn_x);
+	BN_free(bn_y);
+	EC_POINT_free(ecp);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_eckey(p1, eck), 0);
+	ASSERT_INT_EQ(sshbuf_get_string_direct(p1, &d, &s), 0);
+	ASSERT_SIZE_T_EQ(s, sizeof(expec256));
+	ASSERT_MEM_EQ(d, expec256, sizeof(expec256));
+	sshbuf_free(p1);
+	EC_KEY_free(eck);
+	TEST_DONE();
+
+	TEST_START("sshbuf_get_ec");
+	eck = EC_KEY_new_by_curve_name(ec256_nid);
+	ASSERT_PTR_NE(eck, NULL);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_string(p1, expec256, sizeof(expec256)), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expec256) + 4);
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0);
+	ASSERT_INT_EQ(sshbuf_get_eckey(p1, eck), 0);
+	bn_x = BN_new();
+	bn_y = BN_new();
+	ASSERT_PTR_NE(bn_x, NULL);
+	ASSERT_PTR_NE(bn_y, NULL);
+	ASSERT_INT_EQ(EC_POINT_get_affine_coordinates_GFp(
+	    EC_KEY_get0_group(eck), EC_KEY_get0_public_key(eck),
+	    bn_x, bn_y, NULL), 1);
+	MKBN(ec256_x, bn);
+	MKBN(ec256_y, bn2);
+	ASSERT_INT_EQ(BN_cmp(bn_x, bn), 0);
+	ASSERT_INT_EQ(BN_cmp(bn_y, bn2), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	sshbuf_free(p1);
+	EC_KEY_free(eck);
+	BN_free(bn_x);
+	BN_free(bn_y);
+	BN_free(bn);
+	BN_free(bn2);
+	TEST_DONE();
+}
+
diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c b/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c
new file mode 100644
index 0000000..a382ee1
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c
@@ -0,0 +1,120 @@
+/* 	$OpenBSD: test_sshbuf_getput_fuzz.c,v 1.2 2014/05/02 02:54:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/objects.h>
+
+#include "test_helper.h"
+#include "ssherr.h"
+#include "sshbuf.h"
+
+void sshbuf_getput_fuzz_tests(void);
+
+static void
+attempt_parse_blob(u_char *blob, size_t len)
+{
+	struct sshbuf *p1;
+	BIGNUM *bn;
+	EC_KEY *eck;
+	u_char *s;
+	size_t l;
+	u_int8_t u8;
+	u_int16_t u16;
+	u_int32_t u32;
+	u_int64_t u64;
+
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put(p1, blob, len), 0);
+	sshbuf_get_u8(p1, &u8);
+	sshbuf_get_u16(p1, &u16);
+	sshbuf_get_u32(p1, &u32);
+	sshbuf_get_u64(p1, &u64);
+	if (sshbuf_get_string(p1, &s, &l) == 0) {
+		bzero(s, l);
+		free(s);
+	}
+	bn = BN_new();
+	sshbuf_get_bignum1(p1, bn);
+	BN_clear_free(bn);
+	bn = BN_new();
+	sshbuf_get_bignum2(p1, bn);
+	BN_clear_free(bn);
+	eck = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+	ASSERT_PTR_NE(eck, NULL);
+	sshbuf_get_eckey(p1, eck);
+	EC_KEY_free(eck);
+	sshbuf_free(p1);
+}
+
+
+static void
+onerror(void *fuzz)
+{
+	fprintf(stderr, "Failed during fuzz:\n");
+	fuzz_dump((struct fuzz *)fuzz);
+}
+
+void
+sshbuf_getput_fuzz_tests(void)
+{
+	u_char blob[] = {
+		/* u8 */
+		0xd0,
+		/* u16 */
+		0xc0, 0xde,
+		/* u32 */
+		0xfa, 0xce, 0xde, 0xad,
+		/* u64 */
+		0xfe, 0xed, 0xac, 0x1d, 0x1f, 0x1c, 0xbe, 0xef,
+		/* string */
+		0x00, 0x00, 0x00, 0x09,
+		'O', ' ', 'G', 'o', 'r', 'g', 'o', 'n', '!',
+		/* bignum1 */
+		0x79,
+		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+		/* bignum2 */
+		0x00, 0x00, 0x00, 0x14,
+		0x00,
+		0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80,
+		0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00,
+		0x7f, 0xff, 0x11,
+		/* EC point (NIST-256 curve) */
+		0x00, 0x00, 0x00, 0x41,
+		0x04,
+		0x0c, 0x82, 0x80, 0x04, 0x83, 0x9d, 0x01, 0x06,
+		0xaa, 0x59, 0x57, 0x52, 0x16, 0x19, 0x13, 0x57,
+		0x34, 0xb4, 0x51, 0x45, 0x9d, 0xad, 0xb5, 0x86,
+		0x67, 0x7e, 0xf9, 0xdf, 0x55, 0x78, 0x49, 0x99,
+		0x4d, 0x19, 0x6b, 0x50, 0xf0, 0xb4, 0xe9, 0x4b,
+		0x3c, 0x73, 0xe3, 0xa9, 0xd4, 0xcd, 0x9d, 0xf2,
+		0xc8, 0xf9, 0xa3, 0x5e, 0x42, 0xbd, 0xd0, 0x47,
+		0x55, 0x0f, 0x69, 0xd8, 0x0e, 0xc2, 0x3c, 0xd4,
+	};
+	struct fuzz *fuzz;
+
+	TEST_START("fuzz blob parsing");
+	fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_2_BIT_FLIP |
+	    FUZZ_1_BYTE_FLIP | FUZZ_2_BYTE_FLIP |
+	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END, blob, sizeof(blob));
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz))
+		attempt_parse_blob(blob, sizeof(blob));
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+	TEST_ONERROR(NULL, NULL);
+}
+
diff --git a/regress/unittests/sshbuf/test_sshbuf_misc.c b/regress/unittests/sshbuf/test_sshbuf_misc.c
new file mode 100644
index 0000000..a5b1ab2
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_misc.c
@@ -0,0 +1,134 @@
+/* 	$OpenBSD: test_sshbuf_misc.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_helper.h"
+
+#include "sshbuf.h"
+
+void sshbuf_misc_tests(void);
+
+void
+sshbuf_misc_tests(void)
+{
+	struct sshbuf *p1;
+	char tmp[512], *p;
+	FILE *out;
+	size_t sz;
+
+	TEST_START("sshbuf_dump");
+	out = tmpfile();
+	ASSERT_PTR_NE(out, NULL);
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0);
+	sshbuf_dump(p1, out);
+	fflush(out);
+	rewind(out);
+	sz = fread(tmp, 1, sizeof(tmp), out);
+	ASSERT_INT_EQ(ferror(out), 0);
+	ASSERT_INT_NE(feof(out), 0);
+	ASSERT_SIZE_T_GT(sz, 0);
+	tmp[sz] = '\0';
+	ASSERT_PTR_NE(strstr(tmp, "12 34 56 78"), NULL);
+	fclose(out);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_dtob16");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0);
+	p = sshbuf_dtob16(p1);
+	ASSERT_PTR_NE(p, NULL);
+	ASSERT_STRING_EQ(p, "12345678");
+	free(p);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_dtob64 len 1");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0);
+	p = sshbuf_dtob64(p1);
+	ASSERT_PTR_NE(p, NULL);
+	ASSERT_STRING_EQ(p, "EQ==");
+	free(p);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_dtob64 len 2");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0);
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x22), 0);
+	p = sshbuf_dtob64(p1);
+	ASSERT_PTR_NE(p, NULL);
+	ASSERT_STRING_EQ(p, "ESI=");
+	free(p);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_dtob64 len 3");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0);
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x22), 0);
+	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x33), 0);
+	p = sshbuf_dtob64(p1);
+	ASSERT_PTR_NE(p, NULL);
+	ASSERT_STRING_EQ(p, "ESIz");
+	free(p);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_dtob64 len 8191");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_reserve(p1, 8192, NULL), 0);
+	bzero(sshbuf_mutable_ptr(p1), 8192);
+	p = sshbuf_dtob64(p1);
+	ASSERT_PTR_NE(p, NULL);
+	ASSERT_SIZE_T_EQ(strlen(p), ((8191 + 2) / 3) * 4);
+	free(p);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_b64tod len 1");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A=="), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+	ASSERT_U8_EQ(*sshbuf_ptr(p1), 0xd0);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_b64tod len 2");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A8="), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+	ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), 0xd00f);
+	sshbuf_free(p1);
+	TEST_DONE();
+
+	TEST_START("sshbuf_b64tod len 4");
+	p1 = sshbuf_new();
+	ASSERT_PTR_NE(p1, NULL);
+	ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A/QDw=="), 0);
+	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+	ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), 0xd00fd00f);
+	sshbuf_free(p1);
+	TEST_DONE();
+}
+
diff --git a/regress/unittests/sshbuf/tests.c b/regress/unittests/sshbuf/tests.c
new file mode 100644
index 0000000..8397e40
--- /dev/null
+++ b/regress/unittests/sshbuf/tests.c
@@ -0,0 +1,28 @@
+/* 	$OpenBSD: tests.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include "test_helper.h"
+
+void sshbuf_tests(void);
+void sshbuf_getput_basic_tests(void);
+void sshbuf_getput_crypto_tests(void);
+void sshbuf_misc_tests(void);
+void sshbuf_fuzz_tests(void);
+void sshbuf_getput_fuzz_tests(void);
+void sshbuf_fixed(void);
+
+void
+tests(void)
+{
+	sshbuf_tests();
+	sshbuf_getput_basic_tests();
+	sshbuf_getput_crypto_tests();
+	sshbuf_misc_tests();
+	sshbuf_fuzz_tests();
+	sshbuf_getput_fuzz_tests();
+	sshbuf_fixed();
+}
diff --git a/regress/unittests/test_helper/Makefile b/regress/unittests/test_helper/Makefile
new file mode 100644
index 0000000..3e90903
--- /dev/null
+++ b/regress/unittests/test_helper/Makefile
@@ -0,0 +1,13 @@
+#	$OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $
+
+LIB=	test_helper
+SRCS=	test_helper.c fuzz.c
+
+DEBUGLIBS= no
+NOPROFILE= yes
+NOPIC=	yes
+
+install:
+	@echo -n
+
+.include <bsd.lib.mk>
diff --git a/regress/unittests/test_helper/fuzz.c b/regress/unittests/test_helper/fuzz.c
new file mode 100644
index 0000000..b64af24
--- /dev/null
+++ b/regress/unittests/test_helper/fuzz.c
@@ -0,0 +1,374 @@
+/*	$OpenBSD: fuzz.c,v 1.3 2014/05/02 09:41:32 andre Exp $	*/
+/*
+ * Copyright (c) 2011 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.
+ */
+
+/* Utility functions/framework for fuzz tests */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "test_helper.h"
+
+/* #define FUZZ_DEBUG */
+
+#ifdef FUZZ_DEBUG
+# define FUZZ_DBG(x) do { \
+		printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \
+		printf x; \
+		printf("\n"); \
+		fflush(stdout); \
+	} while (0)
+#else
+# define FUZZ_DBG(x)
+#endif
+
+/* For brevity later */
+typedef unsigned long long fuzz_ullong;
+
+/* For base-64 fuzzing */
+static const char fuzz_b64chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+struct fuzz {
+	/* Fuzz method currently in use */
+	int strategy;
+
+	/* Fuzz methods remaining */
+	int strategies;
+
+	/* Original seed data blob */
+	void *seed;
+	size_t slen;
+
+	/* Current working copy of seed with fuzz mutations applied */
+	u_char *fuzzed;
+
+	/* Used by fuzz methods */
+	size_t o1, o2;
+};
+
+static const char *
+fuzz_ntop(u_int n)
+{
+	switch (n) {
+	case 0:
+		return "NONE";
+	case FUZZ_1_BIT_FLIP:
+		return "FUZZ_1_BIT_FLIP";
+	case FUZZ_2_BIT_FLIP:
+		return "FUZZ_2_BIT_FLIP";
+	case FUZZ_1_BYTE_FLIP:
+		return "FUZZ_1_BYTE_FLIP";
+	case FUZZ_2_BYTE_FLIP:
+		return "FUZZ_2_BYTE_FLIP";
+	case FUZZ_TRUNCATE_START:
+		return "FUZZ_TRUNCATE_START";
+	case FUZZ_TRUNCATE_END:
+		return "FUZZ_TRUNCATE_END";
+	case FUZZ_BASE64:
+		return "FUZZ_BASE64";
+	default:
+		abort();
+	}
+}
+
+void
+fuzz_dump(struct fuzz *fuzz)
+{
+	u_char *p = fuzz_ptr(fuzz);
+	size_t i, j, len = fuzz_len(fuzz);
+
+	switch (fuzz->strategy) {
+	case FUZZ_1_BIT_FLIP:
+		fprintf(stderr, "%s case %zu of %zu (bit: %zu)\n",
+		    fuzz_ntop(fuzz->strategy),
+		    fuzz->o1, fuzz->slen * 8, fuzz->o1);
+		break;
+	case FUZZ_2_BIT_FLIP:
+		fprintf(stderr, "%s case %llu of %llu (bits: %zu, %zu)\n",
+		    fuzz_ntop(fuzz->strategy),
+		    (((fuzz_ullong)fuzz->o2) * fuzz->slen * 8) + fuzz->o1,
+		    ((fuzz_ullong)fuzz->slen * 8) * fuzz->slen * 8,
+		    fuzz->o1, fuzz->o2);
+		break;
+	case FUZZ_1_BYTE_FLIP:
+		fprintf(stderr, "%s case %zu of %zu (byte: %zu)\n",
+		    fuzz_ntop(fuzz->strategy),
+		    fuzz->o1, fuzz->slen, fuzz->o1);
+		break;
+	case FUZZ_2_BYTE_FLIP:
+		fprintf(stderr, "%s case %llu of %llu (bytes: %zu, %zu)\n",
+		    fuzz_ntop(fuzz->strategy),
+		    (((fuzz_ullong)fuzz->o2) * fuzz->slen) + fuzz->o1,
+		    ((fuzz_ullong)fuzz->slen) * fuzz->slen,
+		    fuzz->o1, fuzz->o2);
+		break;
+	case FUZZ_TRUNCATE_START:
+		fprintf(stderr, "%s case %zu of %zu (offset: %zu)\n",
+		    fuzz_ntop(fuzz->strategy),
+		    fuzz->o1, fuzz->slen, fuzz->o1);
+		break;
+	case FUZZ_TRUNCATE_END:
+		fprintf(stderr, "%s case %zu of %zu (offset: %zu)\n",
+		    fuzz_ntop(fuzz->strategy),
+		    fuzz->o1, fuzz->slen, fuzz->o1);
+		break;
+	case FUZZ_BASE64:
+		assert(fuzz->o2 < sizeof(fuzz_b64chars) - 1);
+		fprintf(stderr, "%s case %llu of %llu (offset: %zu char: %c)\n",
+		    fuzz_ntop(fuzz->strategy),
+		    (fuzz->o1 * (fuzz_ullong)64) + fuzz->o2,
+		    fuzz->slen * (fuzz_ullong)64, fuzz->o1,
+		    fuzz_b64chars[fuzz->o2]);
+		break;
+	default:
+		abort();
+	}
+
+	fprintf(stderr, "fuzz context %p len = %zu\n", fuzz, len);
+	for (i = 0; i < len; i += 16) {
+		fprintf(stderr, "%.4zd: ", i);
+		for (j = i; j < i + 16; j++) {
+			if (j < len)
+				fprintf(stderr, "%02x ", p[j]);
+			else
+				fprintf(stderr, "   ");
+		}
+		fprintf(stderr, " ");
+		for (j = i; j < i + 16; j++) {
+			if (j < len) {
+				if  (isascii(p[j]) && isprint(p[j]))
+					fprintf(stderr, "%c", p[j]);
+				else
+					fprintf(stderr, ".");
+			}
+		}
+		fprintf(stderr, "\n");
+	}
+}
+
+struct fuzz *
+fuzz_begin(u_int strategies, const void *p, size_t l)
+{
+	struct fuzz *ret = calloc(sizeof(*ret), 1);
+
+	assert(p != NULL);
+	assert(ret != NULL);
+	ret->seed = malloc(l);
+	assert(ret->seed != NULL);
+	memcpy(ret->seed, p, l);
+	ret->slen = l;
+	ret->strategies = strategies;
+
+	assert(ret->slen < SIZE_MAX / 8);
+	assert(ret->strategies <= (FUZZ_MAX|(FUZZ_MAX-1)));
+
+	FUZZ_DBG(("begin, ret = %p", ret));
+
+	fuzz_next(ret);
+	return ret;
+}
+
+void
+fuzz_cleanup(struct fuzz *fuzz)
+{
+	FUZZ_DBG(("cleanup, fuzz = %p", fuzz));
+	assert(fuzz != NULL);
+	assert(fuzz->seed != NULL);
+	assert(fuzz->fuzzed != NULL);
+	free(fuzz->seed);
+	free(fuzz->fuzzed);
+	free(fuzz);
+}
+
+static int
+fuzz_strategy_done(struct fuzz *fuzz)
+{
+	FUZZ_DBG(("fuzz = %p, strategy = %s, o1 = %zu, o2 = %zu, slen = %zu",
+	    fuzz, fuzz_ntop(fuzz->strategy), fuzz->o1, fuzz->o2, fuzz->slen));
+
+	switch (fuzz->strategy) {
+	case FUZZ_1_BIT_FLIP:
+		return fuzz->o1 >= fuzz->slen * 8;
+	case FUZZ_2_BIT_FLIP:
+		return fuzz->o2 >= fuzz->slen * 8;
+	case FUZZ_2_BYTE_FLIP:
+		return fuzz->o2 >= fuzz->slen;
+	case FUZZ_1_BYTE_FLIP:
+	case FUZZ_TRUNCATE_START:
+	case FUZZ_TRUNCATE_END:
+	case FUZZ_BASE64:
+		return fuzz->o1 >= fuzz->slen;
+	default:
+		abort();
+	}
+}
+
+void
+fuzz_next(struct fuzz *fuzz)
+{
+	u_int i;
+
+	FUZZ_DBG(("start, fuzz = %p, strategy = %s, strategies = 0x%lx, "
+	    "o1 = %zu, o2 = %zu, slen = %zu", fuzz, fuzz_ntop(fuzz->strategy),
+	    (u_long)fuzz->strategies, fuzz->o1, fuzz->o2, fuzz->slen));
+
+	if (fuzz->strategy == 0 || fuzz_strategy_done(fuzz)) {
+		/* If we are just starting out, we need to allocate too */
+		if (fuzz->fuzzed == NULL) {
+			FUZZ_DBG(("alloc"));
+			fuzz->fuzzed = calloc(fuzz->slen, 1);
+		}
+		/* Pick next strategy */
+		FUZZ_DBG(("advance"));
+		for (i = 1; i <= FUZZ_MAX; i <<= 1) {
+			if ((fuzz->strategies & i) != 0) {
+				fuzz->strategy = i;
+				break;
+			}
+		}
+		FUZZ_DBG(("selected = %u", fuzz->strategy));
+		if (fuzz->strategy == 0) {
+			FUZZ_DBG(("done, no more strategies"));
+			return;
+		}
+		fuzz->strategies &= ~(fuzz->strategy);
+		fuzz->o1 = fuzz->o2 = 0;
+	}
+
+	assert(fuzz->fuzzed != NULL);
+
+	switch (fuzz->strategy) {
+	case FUZZ_1_BIT_FLIP:
+		assert(fuzz->o1 / 8 < fuzz->slen);
+		memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
+		fuzz->fuzzed[fuzz->o1 / 8] ^= 1 << (fuzz->o1 % 8);
+		fuzz->o1++;
+		break;
+	case FUZZ_2_BIT_FLIP:
+		assert(fuzz->o1 / 8 < fuzz->slen);
+		assert(fuzz->o2 / 8 < fuzz->slen);
+		memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
+		fuzz->fuzzed[fuzz->o1 / 8] ^= 1 << (fuzz->o1 % 8);
+		fuzz->fuzzed[fuzz->o2 / 8] ^= 1 << (fuzz->o2 % 8);
+		fuzz->o1++;
+		if (fuzz->o1 >= fuzz->slen * 8) {
+			fuzz->o1 = 0;
+			fuzz->o2++;
+		}
+		break;
+	case FUZZ_1_BYTE_FLIP:
+		assert(fuzz->o1 < fuzz->slen);
+		memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
+		fuzz->fuzzed[fuzz->o1] ^= 0xff;
+		fuzz->o1++;
+		break;
+	case FUZZ_2_BYTE_FLIP:
+		assert(fuzz->o1 < fuzz->slen);
+		assert(fuzz->o2 < fuzz->slen);
+		memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
+		fuzz->fuzzed[fuzz->o1] ^= 0xff;
+		fuzz->fuzzed[fuzz->o2] ^= 0xff;
+		fuzz->o1++;
+		if (fuzz->o1 >= fuzz->slen) {
+			fuzz->o1 = 0;
+			fuzz->o2++;
+		}
+		break;
+	case FUZZ_TRUNCATE_START:
+	case FUZZ_TRUNCATE_END:
+		assert(fuzz->o1 < fuzz->slen);
+		memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
+		fuzz->o1++;
+		break;
+	case FUZZ_BASE64:
+		assert(fuzz->o1 < fuzz->slen);
+		assert(fuzz->o2 < sizeof(fuzz_b64chars) - 1);
+		memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
+		fuzz->fuzzed[fuzz->o1] = fuzz_b64chars[fuzz->o2];
+		fuzz->o2++;
+		if (fuzz->o2 >= sizeof(fuzz_b64chars) - 1) {
+			fuzz->o2 = 0;
+			fuzz->o1++;
+		}
+		break;
+	default:
+		abort();
+	}
+
+	FUZZ_DBG(("done, fuzz = %p, strategy = %s, strategies = 0x%lx, "
+	    "o1 = %zu, o2 = %zu, slen = %zu", fuzz, fuzz_ntop(fuzz->strategy),
+	    (u_long)fuzz->strategies, fuzz->o1, fuzz->o2, fuzz->slen));
+}
+
+int
+fuzz_done(struct fuzz *fuzz)
+{
+	FUZZ_DBG(("fuzz = %p, strategies = 0x%lx", fuzz,
+	    (u_long)fuzz->strategies));
+
+	return fuzz_strategy_done(fuzz) && fuzz->strategies == 0;
+}
+
+size_t
+fuzz_len(struct fuzz *fuzz)
+{
+	assert(fuzz->fuzzed != NULL);
+	switch (fuzz->strategy) {
+	case FUZZ_1_BIT_FLIP:
+	case FUZZ_2_BIT_FLIP:
+	case FUZZ_1_BYTE_FLIP:
+	case FUZZ_2_BYTE_FLIP:
+	case FUZZ_BASE64:
+		return fuzz->slen;
+	case FUZZ_TRUNCATE_START:
+	case FUZZ_TRUNCATE_END:
+		assert(fuzz->o1 <= fuzz->slen);
+		return fuzz->slen - fuzz->o1;
+	default:
+		abort();
+	}
+}
+
+u_char *
+fuzz_ptr(struct fuzz *fuzz)
+{
+	assert(fuzz->fuzzed != NULL);
+	switch (fuzz->strategy) {
+	case FUZZ_1_BIT_FLIP:
+	case FUZZ_2_BIT_FLIP:
+	case FUZZ_1_BYTE_FLIP:
+	case FUZZ_2_BYTE_FLIP:
+	case FUZZ_BASE64:
+		return fuzz->fuzzed;
+	case FUZZ_TRUNCATE_START:
+		assert(fuzz->o1 <= fuzz->slen);
+		return fuzz->fuzzed + fuzz->o1;
+	case FUZZ_TRUNCATE_END:
+		assert(fuzz->o1 <= fuzz->slen);
+		return fuzz->fuzzed;
+	default:
+		abort();
+	}
+}
+
diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c
new file mode 100644
index 0000000..8f0bbde
--- /dev/null
+++ b/regress/unittests/test_helper/test_helper.c
@@ -0,0 +1,452 @@
+/*	$OpenBSD: test_helper.c,v 1.2 2014/05/02 09:41:32 andre Exp $	*/
+/*
+ * Copyright (c) 2011 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.
+ */
+
+/* Utility functions/framework for regress tests */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include <openssl/bn.h>
+
+#include <vis.h>
+
+#include "test_helper.h"
+
+#define TEST_CHECK_INT(r, pred) do {		\
+		switch (pred) {			\
+		case TEST_EQ:			\
+			if (r == 0)		\
+				return;		\
+			break;			\
+		case TEST_NE:			\
+			if (r != 0)		\
+				return;		\
+			break;			\
+		case TEST_LT:			\
+			if (r < 0)		\
+				return;		\
+			break;			\
+		case TEST_LE:			\
+			if (r <= 0)		\
+				return;		\
+			break;			\
+		case TEST_GT:			\
+			if (r > 0)		\
+				return;		\
+			break;			\
+		case TEST_GE:			\
+			if (r >= 0)		\
+				return;		\
+			break;			\
+		default:			\
+			abort();		\
+		}				\
+	} while (0)
+
+#define TEST_CHECK(x1, x2, pred) do {		\
+		switch (pred) {			\
+		case TEST_EQ:			\
+			if (x1 == x2)		\
+				return;		\
+			break;			\
+		case TEST_NE:			\
+			if (x1 != x2)		\
+				return;		\
+			break;			\
+		case TEST_LT:			\
+			if (x1 < x2)		\
+				return;		\
+			break;			\
+		case TEST_LE:			\
+			if (x1 <= x2)		\
+				return;		\
+			break;			\
+		case TEST_GT:			\
+			if (x1 > x2)		\
+				return;		\
+			break;			\
+		case TEST_GE:			\
+			if (x1 >= x2)		\
+				return;		\
+			break;			\
+		default:			\
+			abort();		\
+		}				\
+	} while (0)
+
+extern char *__progname;
+
+static int verbose_mode = 0;
+static int quiet_mode = 0;
+static char *active_test_name = NULL;
+static u_int test_number = 0;
+static test_onerror_func_t *test_onerror = NULL;
+static void *onerror_ctx = NULL;
+static const char *data_dir = NULL;
+
+int
+main(int argc, char **argv)
+{
+	int ch;
+
+	while ((ch = getopt(argc, argv, "vqd:")) != -1) {
+		switch (ch) {
+		case 'd':
+			data_dir = optarg;
+			break;
+		case 'q':
+			verbose_mode = 0;
+			quiet_mode = 1;
+			break;
+		case 'v':
+			verbose_mode = 1;
+			quiet_mode = 0;
+			break;
+		default:
+			fprintf(stderr, "Unrecognised command line option\n");
+			fprintf(stderr, "Usage: %s [-v]\n", __progname);
+			exit(1);
+		}
+	}
+	setvbuf(stdout, NULL, _IONBF, 0);
+	if (!quiet_mode)
+		printf("%s: ", __progname);
+	if (verbose_mode)
+		printf("\n");
+
+	tests();
+
+	if (!quiet_mode)
+		printf(" %u tests ok\n", test_number);
+	return 0;
+}
+
+const char *
+test_data_file(const char *name)
+{
+	static char ret[PATH_MAX];
+
+	if (data_dir != NULL)
+		snprintf(ret, sizeof(ret), "%s/%s", data_dir, name);
+	else
+		strlcpy(ret, name, sizeof(ret));
+	if (access(ret, F_OK) != 0) {
+		fprintf(stderr, "Cannot access data file %s: %s\n",
+		    ret, strerror(errno));
+		exit(1);
+	}
+	return ret;
+}
+
+void
+test_start(const char *n)
+{
+	assert(active_test_name == NULL);
+	assert((active_test_name = strdup(n)) != NULL);
+	if (verbose_mode)
+		printf("test %u - \"%s\": ", test_number, active_test_name);
+	test_number++;
+}
+
+void
+set_onerror_func(test_onerror_func_t *f, void *ctx)
+{
+	test_onerror = f;
+	onerror_ctx = ctx;
+}
+
+void
+test_done(void)
+{
+	assert(active_test_name != NULL);
+	free(active_test_name);
+	active_test_name = NULL;
+	if (verbose_mode)
+		printf("OK\n");
+	else if (!quiet_mode) {
+		printf(".");
+		fflush(stdout);
+	}
+}
+
+void
+ssl_err_check(const char *file, int line)
+{
+	long openssl_error = ERR_get_error();
+
+	if (openssl_error == 0)
+		return;
+
+	fprintf(stderr, "\n%s:%d: uncaught OpenSSL error: %s",
+	    file, line, ERR_error_string(openssl_error, NULL));
+	abort();
+}
+
+static const char *
+pred_name(enum test_predicate p)
+{
+	switch (p) {
+	case TEST_EQ:
+		return "EQ";
+	case TEST_NE:
+		return "NE";
+	case TEST_LT:
+		return "LT";
+	case TEST_LE:
+		return "LE";
+	case TEST_GT:
+		return "GT";
+	case TEST_GE:
+		return "GE";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static void
+test_die(void)
+{
+	if (test_onerror != NULL)
+		test_onerror(onerror_ctx);
+	abort();
+}
+
+static void
+test_header(const char *file, int line, const char *a1, const char *a2,
+    const char *name, enum test_predicate pred)
+{
+	fprintf(stderr, "\n%s:%d test #%u \"%s\"\n", 
+	    file, line, test_number, active_test_name);
+	fprintf(stderr, "ASSERT_%s_%s(%s%s%s) failed:\n",
+	    name, pred_name(pred), a1,
+	    a2 != NULL ? ", " : "", a2 != NULL ? a2 : "");
+}
+
+void
+assert_bignum(const char *file, int line, const char *a1, const char *a2,
+    const BIGNUM *aa1, const BIGNUM *aa2, enum test_predicate pred)
+{
+	int r = BN_cmp(aa1, aa2);
+
+	TEST_CHECK_INT(r, pred);
+	test_header(file, line, a1, a2, "BIGNUM", pred);
+	fprintf(stderr, "%12s = 0x%s\n", a1, BN_bn2hex(aa1));
+	fprintf(stderr, "%12s = 0x%s\n", a2, BN_bn2hex(aa2));
+	test_die();
+}
+
+void
+assert_string(const char *file, int line, const char *a1, const char *a2,
+    const char *aa1, const char *aa2, enum test_predicate pred)
+{
+	int r = strcmp(aa1, aa2);
+
+	TEST_CHECK_INT(r, pred);
+	test_header(file, line, a1, a2, "STRING", pred);
+	fprintf(stderr, "%12s = %s (len %zu)\n", a1, aa1, strlen(aa1));
+	fprintf(stderr, "%12s = %s (len %zu)\n", a2, aa2, strlen(aa2));
+	test_die();
+}
+
+static char *
+tohex(const void *_s, size_t l)
+{
+	u_int8_t *s = (u_int8_t *)_s;
+	size_t i, j;
+	const char *hex = "0123456789abcdef";
+	char *r = malloc((l * 2) + 1);
+
+	assert(r != NULL);
+	for (i = j = 0; i < l; i++) {
+		r[j++] = hex[(s[i] >> 4) & 0xf];
+		r[j++] = hex[s[i] & 0xf];
+	}
+	r[j] = '\0';
+	return r;
+}
+
+void
+assert_mem(const char *file, int line, const char *a1, const char *a2,
+    const void *aa1, const void *aa2, size_t l, enum test_predicate pred)
+{
+	int r = memcmp(aa1, aa2, l);
+
+	TEST_CHECK_INT(r, pred);
+	test_header(file, line, a1, a2, "STRING", pred);
+	fprintf(stderr, "%12s = %s (len %zu)\n", a1, tohex(aa1, MIN(l, 256)), l);
+	fprintf(stderr, "%12s = %s (len %zu)\n", a2, tohex(aa2, MIN(l, 256)), l);
+	test_die();
+}
+
+static int
+memvalcmp(const u_int8_t *s, u_char v, size_t l, size_t *where)
+{
+	size_t i;
+
+	for (i = 0; i < l; i++) {
+		if (s[i] != v) {
+			*where = i;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void
+assert_mem_filled(const char *file, int line, const char *a1,
+    const void *aa1, u_char v, size_t l, enum test_predicate pred)
+{
+	size_t where = -1;
+	int r = memvalcmp(aa1, v, l, &where);
+	char tmp[64];
+
+	if (l == 0)
+		return;
+	TEST_CHECK_INT(r, pred);
+	test_header(file, line, a1, NULL, "MEM_ZERO", pred);
+	fprintf(stderr, "%20s = %s%s (len %zu)\n", a1,
+	    tohex(aa1, MIN(l, 20)), l > 20 ? "..." : "", l);
+	snprintf(tmp, sizeof(tmp), "(%s)[%zu]", a1, where);
+	fprintf(stderr, "%20s = 0x%02x (expected 0x%02x)\n", tmp,
+	    ((u_char *)aa1)[where], v);
+	test_die();
+}
+
+void
+assert_int(const char *file, int line, const char *a1, const char *a2,
+    int aa1, int aa2, enum test_predicate pred)
+{
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "INT", pred);
+	fprintf(stderr, "%12s = %d\n", a1, aa1);
+	fprintf(stderr, "%12s = %d\n", a2, aa2);
+	test_die();
+}
+
+void
+assert_size_t(const char *file, int line, const char *a1, const char *a2,
+    size_t aa1, size_t aa2, enum test_predicate pred)
+{
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "SIZE_T", pred);
+	fprintf(stderr, "%12s = %zu\n", a1, aa1);
+	fprintf(stderr, "%12s = %zu\n", a2, aa2);
+	test_die();
+}
+
+void
+assert_u_int(const char *file, int line, const char *a1, const char *a2,
+    u_int aa1, u_int aa2, enum test_predicate pred)
+{
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "U_INT", pred);
+	fprintf(stderr, "%12s = %u / 0x%x\n", a1, aa1, aa1);
+	fprintf(stderr, "%12s = %u / 0x%x\n", a2, aa2, aa2);
+	test_die();
+}
+
+void
+assert_long_long(const char *file, int line, const char *a1, const char *a2,
+    long long aa1, long long aa2, enum test_predicate pred)
+{
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "LONG LONG", pred);
+	fprintf(stderr, "%12s = %lld / 0x%llx\n", a1, aa1, aa1);
+	fprintf(stderr, "%12s = %lld / 0x%llx\n", a2, aa2, aa2);
+	test_die();
+}
+
+void
+assert_char(const char *file, int line, const char *a1, const char *a2,
+    char aa1, char aa2, enum test_predicate pred)
+{
+	char buf[8];
+
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "CHAR", pred);
+	fprintf(stderr, "%12s = '%s' / 0x02%x\n", a1,
+	    vis(buf, aa1, VIS_SAFE|VIS_NL|VIS_TAB|VIS_OCTAL, 0), aa1);
+	fprintf(stderr, "%12s = '%s' / 0x02%x\n", a1,
+	    vis(buf, aa2, VIS_SAFE|VIS_NL|VIS_TAB|VIS_OCTAL, 0), aa2);
+	test_die();
+}
+
+void
+assert_u8(const char *file, int line, const char *a1, const char *a2,
+    u_int8_t aa1, u_int8_t aa2, enum test_predicate pred)
+{
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "U8", pred);
+	fprintf(stderr, "%12s = 0x%02x %u\n", a1, aa1, aa1);
+	fprintf(stderr, "%12s = 0x%02x %u\n", a2, aa2, aa2);
+	test_die();
+}
+
+void
+assert_u16(const char *file, int line, const char *a1, const char *a2,
+    u_int16_t aa1, u_int16_t aa2, enum test_predicate pred)
+{
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "U16", pred);
+	fprintf(stderr, "%12s = 0x%04x %u\n", a1, aa1, aa1);
+	fprintf(stderr, "%12s = 0x%04x %u\n", a2, aa2, aa2);
+	test_die();
+}
+
+void
+assert_u32(const char *file, int line, const char *a1, const char *a2,
+    u_int32_t aa1, u_int32_t aa2, enum test_predicate pred)
+{
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "U32", pred);
+	fprintf(stderr, "%12s = 0x%08x %u\n", a1, aa1, aa1);
+	fprintf(stderr, "%12s = 0x%08x %u\n", a2, aa2, aa2);
+	test_die();
+}
+
+void
+assert_u64(const char *file, int line, const char *a1, const char *a2,
+    u_int64_t aa1, u_int64_t aa2, enum test_predicate pred)
+{
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "U64", pred);
+	fprintf(stderr, "%12s = 0x%016llx %llu\n", a1,
+	    (unsigned long long)aa1, (unsigned long long)aa1);
+	fprintf(stderr, "%12s = 0x%016llx %llu\n", a2,
+	    (unsigned long long)aa2, (unsigned long long)aa2);
+	test_die();
+}
+
+void
+assert_ptr(const char *file, int line, const char *a1, const char *a2,
+    const void *aa1, const void *aa2, enum test_predicate pred)
+{
+	TEST_CHECK(aa1, aa2, pred);
+	test_header(file, line, a1, a2, "PTR", pred);
+	fprintf(stderr, "%12s = %p\n", a1, aa1);
+	fprintf(stderr, "%12s = %p\n", a2, aa2);
+	test_die();
+}
+
diff --git a/regress/unittests/test_helper/test_helper.h b/regress/unittests/test_helper/test_helper.h
new file mode 100644
index 0000000..6ead92a
--- /dev/null
+++ b/regress/unittests/test_helper/test_helper.h
@@ -0,0 +1,288 @@
+/*	$OpenBSD: test_helper.h,v 1.3 2014/05/02 09:41:32 andre Exp $	*/
+/*
+ * Copyright (c) 2011 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.
+ */
+
+/* Utility functions/framework for regress tests */
+
+#ifndef _TEST_HELPER_H
+#define _TEST_HELPER_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+
+enum test_predicate {
+	TEST_EQ, TEST_NE, TEST_LT, TEST_LE, TEST_GT, TEST_GE
+};
+typedef void (test_onerror_func_t)(void *);
+
+/* Supplied by test suite */
+void tests(void);
+
+const char *test_data_file(const char *name);
+void test_start(const char *n);
+void set_onerror_func(test_onerror_func_t *f, void *ctx);
+void test_done(void);
+void ssl_err_check(const char *file, int line);
+void assert_bignum(const char *file, int line,
+    const char *a1, const char *a2,
+    const BIGNUM *aa1, const BIGNUM *aa2, enum test_predicate pred);
+void assert_string(const char *file, int line,
+    const char *a1, const char *a2,
+    const char *aa1, const char *aa2, enum test_predicate pred);
+void assert_mem(const char *file, int line,
+    const char *a1, const char *a2,
+    const void *aa1, const void *aa2, size_t l, enum test_predicate pred);
+void assert_mem_filled(const char *file, int line,
+    const char *a1,
+    const void *aa1, u_char v, size_t l, enum test_predicate pred);
+void assert_int(const char *file, int line,
+    const char *a1, const char *a2,
+    int aa1, int aa2, enum test_predicate pred);
+void assert_size_t(const char *file, int line,
+    const char *a1, const char *a2,
+    size_t aa1, size_t aa2, enum test_predicate pred);
+void assert_u_int(const char *file, int line,
+    const char *a1, const char *a2,
+    u_int aa1, u_int aa2, enum test_predicate pred);
+void assert_long_long(const char *file, int line,
+    const char *a1, const char *a2,
+    long long aa1, long long aa2, enum test_predicate pred);
+void assert_char(const char *file, int line,
+    const char *a1, const char *a2,
+    char aa1, char aa2, enum test_predicate pred);
+void assert_ptr(const char *file, int line,
+    const char *a1, const char *a2,
+    const void *aa1, const void *aa2, enum test_predicate pred);
+void assert_u8(const char *file, int line,
+    const char *a1, const char *a2,
+    u_int8_t aa1, u_int8_t aa2, enum test_predicate pred);
+void assert_u16(const char *file, int line,
+    const char *a1, const char *a2,
+    u_int16_t aa1, u_int16_t aa2, enum test_predicate pred);
+void assert_u32(const char *file, int line,
+    const char *a1, const char *a2,
+    u_int32_t aa1, u_int32_t aa2, enum test_predicate pred);
+void assert_u64(const char *file, int line,
+    const char *a1, const char *a2,
+    u_int64_t aa1, u_int64_t aa2, enum test_predicate pred);
+
+#define TEST_START(n)			test_start(n)
+#define TEST_DONE()			test_done()
+#define TEST_ONERROR(f, c)		set_onerror_func(f, c)
+#define SSL_ERR_CHECK() 		ssl_err_check(__FILE__, __LINE__)
+
+#define ASSERT_BIGNUM_EQ(a1, a2) \
+	assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_STRING_EQ(a1, a2) \
+	assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_MEM_EQ(a1, a2, l) \
+	assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_EQ)
+#define ASSERT_MEM_FILLED_EQ(a1, c, l) \
+	assert_mem_filled(__FILE__, __LINE__, #a1, a1, c, l, TEST_EQ)
+#define ASSERT_MEM_ZERO_EQ(a1, l) \
+	assert_mem_filled(__FILE__, __LINE__, #a1, a1, '\0', l, TEST_EQ)
+#define ASSERT_INT_EQ(a1, a2) \
+	assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_SIZE_T_EQ(a1, a2) \
+	assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_U_INT_EQ(a1, a2) \
+	assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_LONG_LONG_EQ(a1, a2) \
+	assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_CHAR_EQ(a1, a2) \
+	assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_PTR_EQ(a1, a2) \
+	assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_U8_EQ(a1, a2) \
+	assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_U16_EQ(a1, a2) \
+	assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_U32_EQ(a1, a2) \
+	assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+#define ASSERT_U64_EQ(a1, a2) \
+	assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
+
+#define ASSERT_BIGNUM_NE(a1, a2) \
+	assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_STRING_NE(a1, a2) \
+	assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_MEM_NE(a1, a2, l) \
+	assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_NE)
+#define ASSERT_MEM_ZERO_NE(a1, l) \
+	assert_mem_filled(__FILE__, __LINE__, #a1, a1, '\0', l, TEST_NE)
+#define ASSERT_INT_NE(a1, a2) \
+	assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_SIZE_T_NE(a1, a2) \
+	assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_U_INT_NE(a1, a2) \
+	assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_LONG_LONG_NE(a1, a2) \
+	assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_CHAR_NE(a1, a2) \
+	assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_PTR_NE(a1, a2) \
+	assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_U8_NE(a1, a2) \
+	assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_U16_NE(a1, a2) \
+	assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_U32_NE(a1, a2) \
+	assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+#define ASSERT_U64_NE(a1, a2) \
+	assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
+
+#define ASSERT_BIGNUM_LT(a1, a2) \
+	assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_STRING_LT(a1, a2) \
+	assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_MEM_LT(a1, a2, l) \
+	assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_LT)
+#define ASSERT_INT_LT(a1, a2) \
+	assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_SIZE_T_LT(a1, a2) \
+	assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_U_INT_LT(a1, a2) \
+	assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_LONG_LONG_LT(a1, a2) \
+	assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_CHAR_LT(a1, a2) \
+	assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_PTR_LT(a1, a2) \
+	assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_U8_LT(a1, a2) \
+	assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_U16_LT(a1, a2) \
+	assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_U32_LT(a1, a2) \
+	assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+#define ASSERT_U64_LT(a1, a2) \
+	assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
+
+#define ASSERT_BIGNUM_LE(a1, a2) \
+	assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_STRING_LE(a1, a2) \
+	assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_MEM_LE(a1, a2, l) \
+	assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_LE)
+#define ASSERT_INT_LE(a1, a2) \
+	assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_SIZE_T_LE(a1, a2) \
+	assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_U_INT_LE(a1, a2) \
+	assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_LONG_LONG_LE(a1, a2) \
+	assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_CHAR_LE(a1, a2) \
+	assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_PTR_LE(a1, a2) \
+	assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_U8_LE(a1, a2) \
+	assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_U16_LE(a1, a2) \
+	assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_U32_LE(a1, a2) \
+	assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+#define ASSERT_U64_LE(a1, a2) \
+	assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
+
+#define ASSERT_BIGNUM_GT(a1, a2) \
+	assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_STRING_GT(a1, a2) \
+	assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_MEM_GT(a1, a2, l) \
+	assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_GT)
+#define ASSERT_INT_GT(a1, a2) \
+	assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_SIZE_T_GT(a1, a2) \
+	assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_U_INT_GT(a1, a2) \
+	assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_LONG_LONG_GT(a1, a2) \
+	assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_CHAR_GT(a1, a2) \
+	assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_PTR_GT(a1, a2) \
+	assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_U8_GT(a1, a2) \
+	assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_U16_GT(a1, a2) \
+	assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_U32_GT(a1, a2) \
+	assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+#define ASSERT_U64_GT(a1, a2) \
+	assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
+
+#define ASSERT_BIGNUM_GE(a1, a2) \
+	assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_STRING_GE(a1, a2) \
+	assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_MEM_GE(a1, a2, l) \
+	assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_GE)
+#define ASSERT_INT_GE(a1, a2) \
+	assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_SIZE_T_GE(a1, a2) \
+	assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_U_INT_GE(a1, a2) \
+	assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_LONG_LONG_GE(a1, a2) \
+	assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_CHAR_GE(a1, a2) \
+	assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_PTR_GE(a1, a2) \
+	assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_U8_GE(a1, a2) \
+	assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_U16_GE(a1, a2) \
+	assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_U32_GE(a1, a2) \
+	assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+#define ASSERT_U64_GE(a1, a2) \
+	assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
+
+/* Fuzzing support */
+
+struct fuzz;
+#define FUZZ_1_BIT_FLIP		0x00000001	/* Flip one bit at a time */
+#define FUZZ_2_BIT_FLIP		0x00000002	/* Flip two bits at a time */
+#define FUZZ_1_BYTE_FLIP	0x00000004	/* Flip one byte at a time */
+#define FUZZ_2_BYTE_FLIP	0x00000008	/* Flip two bytes at a time */
+#define FUZZ_TRUNCATE_START	0x00000010	/* Truncate from beginning */
+#define FUZZ_TRUNCATE_END	0x00000020	/* Truncate from end */
+#define FUZZ_BASE64		0x00000040	/* Try all base64 chars */
+#define FUZZ_MAX		FUZZ_BASE64
+
+/* Start fuzzing a blob of data with selected strategies (bitmask) */
+struct fuzz *fuzz_begin(u_int strategies, const void *p, size_t l);
+
+/* Free a fuzz context */
+void fuzz_cleanup(struct fuzz *fuzz);
+
+/* Prepare the next fuzz case in the series */
+void fuzz_next(struct fuzz *fuzz);
+
+/* Determine whether the current fuzz sequence is exhausted (nonzero = yes) */
+int fuzz_done(struct fuzz *fuzz);
+
+/* Return the length and a pointer to the current fuzzed case */
+size_t fuzz_len(struct fuzz *fuzz);
+u_char *fuzz_ptr(struct fuzz *fuzz);
+
+/* Dump the current fuzz case to stderr */
+void fuzz_dump(struct fuzz *fuzz);
+#endif /* _TEST_HELPER_H */