- djm@cvs.openbsd.org 2014/06/24 01:14:17
     [Makefile.in regress/Makefile regress/unittests/Makefile]
     [regress/unittests/sshkey/Makefile]
     [regress/unittests/sshkey/common.c]
     [regress/unittests/sshkey/common.h]
     [regress/unittests/sshkey/mktestdata.sh]
     [regress/unittests/sshkey/test_file.c]
     [regress/unittests/sshkey/test_fuzz.c]
     [regress/unittests/sshkey/test_sshkey.c]
     [regress/unittests/sshkey/tests.c]
     [regress/unittests/sshkey/testdata/dsa_1]
     [regress/unittests/sshkey/testdata/dsa_1-cert.fp]
     [regress/unittests/sshkey/testdata/dsa_1-cert.pub]
     [regress/unittests/sshkey/testdata/dsa_1.fp]
     [regress/unittests/sshkey/testdata/dsa_1.fp.bb]
     [regress/unittests/sshkey/testdata/dsa_1.param.g]
     [regress/unittests/sshkey/testdata/dsa_1.param.priv]
     [regress/unittests/sshkey/testdata/dsa_1.param.pub]
     [regress/unittests/sshkey/testdata/dsa_1.pub]
     [regress/unittests/sshkey/testdata/dsa_1_pw]
     [regress/unittests/sshkey/testdata/dsa_2]
     [regress/unittests/sshkey/testdata/dsa_2.fp]
     [regress/unittests/sshkey/testdata/dsa_2.fp.bb]
     [regress/unittests/sshkey/testdata/dsa_2.pub]
     [regress/unittests/sshkey/testdata/dsa_n]
     [regress/unittests/sshkey/testdata/dsa_n_pw]
     [regress/unittests/sshkey/testdata/ecdsa_1]
     [regress/unittests/sshkey/testdata/ecdsa_1-cert.fp]
     [regress/unittests/sshkey/testdata/ecdsa_1-cert.pub]
     [regress/unittests/sshkey/testdata/ecdsa_1.fp]
     [regress/unittests/sshkey/testdata/ecdsa_1.fp.bb]
     [regress/unittests/sshkey/testdata/ecdsa_1.param.curve]
     [regress/unittests/sshkey/testdata/ecdsa_1.param.priv]
     [regress/unittests/sshkey/testdata/ecdsa_1.param.pub]
     [regress/unittests/sshkey/testdata/ecdsa_1.pub]
     [regress/unittests/sshkey/testdata/ecdsa_1_pw]
     [regress/unittests/sshkey/testdata/ecdsa_2]
     [regress/unittests/sshkey/testdata/ecdsa_2.fp]
     [regress/unittests/sshkey/testdata/ecdsa_2.fp.bb]
     [regress/unittests/sshkey/testdata/ecdsa_2.param.curve]
     [regress/unittests/sshkey/testdata/ecdsa_2.param.priv]
     [regress/unittests/sshkey/testdata/ecdsa_2.param.pub]
     [regress/unittests/sshkey/testdata/ecdsa_2.pub]
     [regress/unittests/sshkey/testdata/ecdsa_n]
     [regress/unittests/sshkey/testdata/ecdsa_n_pw]
     [regress/unittests/sshkey/testdata/ed25519_1]
     [regress/unittests/sshkey/testdata/ed25519_1-cert.fp]
     [regress/unittests/sshkey/testdata/ed25519_1-cert.pub]
     [regress/unittests/sshkey/testdata/ed25519_1.fp]
     [regress/unittests/sshkey/testdata/ed25519_1.fp.bb]
     [regress/unittests/sshkey/testdata/ed25519_1.pub]
     [regress/unittests/sshkey/testdata/ed25519_1_pw]
     [regress/unittests/sshkey/testdata/ed25519_2]
     [regress/unittests/sshkey/testdata/ed25519_2.fp]
     [regress/unittests/sshkey/testdata/ed25519_2.fp.bb]
     [regress/unittests/sshkey/testdata/ed25519_2.pub]
     [regress/unittests/sshkey/testdata/pw]
     [regress/unittests/sshkey/testdata/rsa1_1]
     [regress/unittests/sshkey/testdata/rsa1_1.fp]
     [regress/unittests/sshkey/testdata/rsa1_1.fp.bb]
     [regress/unittests/sshkey/testdata/rsa1_1.param.n]
     [regress/unittests/sshkey/testdata/rsa1_1.pub]
     [regress/unittests/sshkey/testdata/rsa1_1_pw]
     [regress/unittests/sshkey/testdata/rsa1_2]
     [regress/unittests/sshkey/testdata/rsa1_2.fp]
     [regress/unittests/sshkey/testdata/rsa1_2.fp.bb]
     [regress/unittests/sshkey/testdata/rsa1_2.param.n]
     [regress/unittests/sshkey/testdata/rsa1_2.pub]
     [regress/unittests/sshkey/testdata/rsa_1]
     [regress/unittests/sshkey/testdata/rsa_1-cert.fp]
     [regress/unittests/sshkey/testdata/rsa_1-cert.pub]
     [regress/unittests/sshkey/testdata/rsa_1.fp]
     [regress/unittests/sshkey/testdata/rsa_1.fp.bb]
     [regress/unittests/sshkey/testdata/rsa_1.param.n]
     [regress/unittests/sshkey/testdata/rsa_1.param.p]
     [regress/unittests/sshkey/testdata/rsa_1.param.q]
     [regress/unittests/sshkey/testdata/rsa_1.pub]
     [regress/unittests/sshkey/testdata/rsa_1_pw]
     [regress/unittests/sshkey/testdata/rsa_2]
     [regress/unittests/sshkey/testdata/rsa_2.fp]
     [regress/unittests/sshkey/testdata/rsa_2.fp.bb]
     [regress/unittests/sshkey/testdata/rsa_2.param.n]
     [regress/unittests/sshkey/testdata/rsa_2.param.p]
     [regress/unittests/sshkey/testdata/rsa_2.param.q]
     [regress/unittests/sshkey/testdata/rsa_2.pub]
     [regress/unittests/sshkey/testdata/rsa_n]
     [regress/unittests/sshkey/testdata/rsa_n_pw]
     unit and fuzz tests for new key API
diff --git a/ChangeLog b/ChangeLog
index 556f369..36109a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -87,6 +87,94 @@
    - djm@cvs.openbsd.org 2014/06/24 01:04:43
      [regress/krl.sh]
      regress test for broken consecutive revoked serial number ranges
+   - djm@cvs.openbsd.org 2014/06/24 01:14:17
+     [Makefile.in regress/Makefile regress/unittests/Makefile]
+     [regress/unittests/sshkey/Makefile]
+     [regress/unittests/sshkey/common.c]
+     [regress/unittests/sshkey/common.h]
+     [regress/unittests/sshkey/mktestdata.sh]
+     [regress/unittests/sshkey/test_file.c]
+     [regress/unittests/sshkey/test_fuzz.c]
+     [regress/unittests/sshkey/test_sshkey.c]
+     [regress/unittests/sshkey/tests.c]
+     [regress/unittests/sshkey/testdata/dsa_1]
+     [regress/unittests/sshkey/testdata/dsa_1-cert.fp]
+     [regress/unittests/sshkey/testdata/dsa_1-cert.pub]
+     [regress/unittests/sshkey/testdata/dsa_1.fp]
+     [regress/unittests/sshkey/testdata/dsa_1.fp.bb]
+     [regress/unittests/sshkey/testdata/dsa_1.param.g]
+     [regress/unittests/sshkey/testdata/dsa_1.param.priv]
+     [regress/unittests/sshkey/testdata/dsa_1.param.pub]
+     [regress/unittests/sshkey/testdata/dsa_1.pub]
+     [regress/unittests/sshkey/testdata/dsa_1_pw]
+     [regress/unittests/sshkey/testdata/dsa_2]
+     [regress/unittests/sshkey/testdata/dsa_2.fp]
+     [regress/unittests/sshkey/testdata/dsa_2.fp.bb]
+     [regress/unittests/sshkey/testdata/dsa_2.pub]
+     [regress/unittests/sshkey/testdata/dsa_n]
+     [regress/unittests/sshkey/testdata/dsa_n_pw]
+     [regress/unittests/sshkey/testdata/ecdsa_1]
+     [regress/unittests/sshkey/testdata/ecdsa_1-cert.fp]
+     [regress/unittests/sshkey/testdata/ecdsa_1-cert.pub]
+     [regress/unittests/sshkey/testdata/ecdsa_1.fp]
+     [regress/unittests/sshkey/testdata/ecdsa_1.fp.bb]
+     [regress/unittests/sshkey/testdata/ecdsa_1.param.curve]
+     [regress/unittests/sshkey/testdata/ecdsa_1.param.priv]
+     [regress/unittests/sshkey/testdata/ecdsa_1.param.pub]
+     [regress/unittests/sshkey/testdata/ecdsa_1.pub]
+     [regress/unittests/sshkey/testdata/ecdsa_1_pw]
+     [regress/unittests/sshkey/testdata/ecdsa_2]
+     [regress/unittests/sshkey/testdata/ecdsa_2.fp]
+     [regress/unittests/sshkey/testdata/ecdsa_2.fp.bb]
+     [regress/unittests/sshkey/testdata/ecdsa_2.param.curve]
+     [regress/unittests/sshkey/testdata/ecdsa_2.param.priv]
+     [regress/unittests/sshkey/testdata/ecdsa_2.param.pub]
+     [regress/unittests/sshkey/testdata/ecdsa_2.pub]
+     [regress/unittests/sshkey/testdata/ecdsa_n]
+     [regress/unittests/sshkey/testdata/ecdsa_n_pw]
+     [regress/unittests/sshkey/testdata/ed25519_1]
+     [regress/unittests/sshkey/testdata/ed25519_1-cert.fp]
+     [regress/unittests/sshkey/testdata/ed25519_1-cert.pub]
+     [regress/unittests/sshkey/testdata/ed25519_1.fp]
+     [regress/unittests/sshkey/testdata/ed25519_1.fp.bb]
+     [regress/unittests/sshkey/testdata/ed25519_1.pub]
+     [regress/unittests/sshkey/testdata/ed25519_1_pw]
+     [regress/unittests/sshkey/testdata/ed25519_2]
+     [regress/unittests/sshkey/testdata/ed25519_2.fp]
+     [regress/unittests/sshkey/testdata/ed25519_2.fp.bb]
+     [regress/unittests/sshkey/testdata/ed25519_2.pub]
+     [regress/unittests/sshkey/testdata/pw]
+     [regress/unittests/sshkey/testdata/rsa1_1]
+     [regress/unittests/sshkey/testdata/rsa1_1.fp]
+     [regress/unittests/sshkey/testdata/rsa1_1.fp.bb]
+     [regress/unittests/sshkey/testdata/rsa1_1.param.n]
+     [regress/unittests/sshkey/testdata/rsa1_1.pub]
+     [regress/unittests/sshkey/testdata/rsa1_1_pw]
+     [regress/unittests/sshkey/testdata/rsa1_2]
+     [regress/unittests/sshkey/testdata/rsa1_2.fp]
+     [regress/unittests/sshkey/testdata/rsa1_2.fp.bb]
+     [regress/unittests/sshkey/testdata/rsa1_2.param.n]
+     [regress/unittests/sshkey/testdata/rsa1_2.pub]
+     [regress/unittests/sshkey/testdata/rsa_1]
+     [regress/unittests/sshkey/testdata/rsa_1-cert.fp]
+     [regress/unittests/sshkey/testdata/rsa_1-cert.pub]
+     [regress/unittests/sshkey/testdata/rsa_1.fp]
+     [regress/unittests/sshkey/testdata/rsa_1.fp.bb]
+     [regress/unittests/sshkey/testdata/rsa_1.param.n]
+     [regress/unittests/sshkey/testdata/rsa_1.param.p]
+     [regress/unittests/sshkey/testdata/rsa_1.param.q]
+     [regress/unittests/sshkey/testdata/rsa_1.pub]
+     [regress/unittests/sshkey/testdata/rsa_1_pw]
+     [regress/unittests/sshkey/testdata/rsa_2]
+     [regress/unittests/sshkey/testdata/rsa_2.fp]
+     [regress/unittests/sshkey/testdata/rsa_2.fp.bb]
+     [regress/unittests/sshkey/testdata/rsa_2.param.n]
+     [regress/unittests/sshkey/testdata/rsa_2.param.p]
+     [regress/unittests/sshkey/testdata/rsa_2.param.q]
+     [regress/unittests/sshkey/testdata/rsa_2.pub]
+     [regress/unittests/sshkey/testdata/rsa_n]
+     [regress/unittests/sshkey/testdata/rsa_n_pw]
+     unit and fuzz tests for new key API
 
 20140618
  - (tim) [openssh/session.c] Work around to get chroot sftp working on UnixWare
diff --git a/Makefile.in b/Makefile.in
index 16659c0..9adc0da 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.360 2014/07/02 05:28:03 djm Exp $
+# $Id: Makefile.in,v 1.361 2014/07/02 07:38:32 djm Exp $
 
 # uncomment if you run a non bourne compatable shell. Ie. csh
 #SHELL = @SH@
@@ -66,10 +66,10 @@
 LIBOPENSSH_OBJS=\
 	ssherr.o \
 	sshbuf.o \
+	sshkey.o \
 	sshbuf-getput-basic.o \
 	sshbuf-misc.o \
-	sshbuf-getput-crypto.o \
-	sshkey.o
+	sshbuf-getput-crypto.o
 
 LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
 	authfd.o authfile.o bufaux.o bufbn.o buffer.o \
@@ -227,6 +227,8 @@
 	rm -f regress/unittests/test_helper/*.o
 	rm -f regress/unittests/sshbuf/*.o
 	rm -f regress/unittests/sshbuf/test_sshbuf
+	rm -f regress/unittests/sshkey/*.o
+	rm -f regress/unittests/sshkey/test_sshkey
 	(cd openbsd-compat && $(MAKE) clean)
 
 distclean:	regressclean
@@ -239,6 +241,8 @@
 	rm -f regress/unittests/test_helper/*.o
 	rm -f regress/unittests/sshbuf/*.o
 	rm -f regress/unittests/sshbuf/test_sshbuf
+	rm -f regress/unittests/sshkey/*.o
+	rm -f regress/unittests/sshkey/test_sshkey
 	(cd openbsd-compat && $(MAKE) distclean)
 	if test -d pkg ; then \
 		rm -fr pkg ; \
@@ -418,6 +422,8 @@
 		mkdir -p `pwd`/regress/unittests/test_helper
 	[ -d `pwd`/regress/unittests/sshbuf ]  || \
 		mkdir -p `pwd`/regress/unittests/sshbuf
+	[ -d `pwd`/regress/unittests/sshkey ]  || \
+		mkdir -p `pwd`/regress/unittests/sshkey
 	[ -f `pwd`/regress/Makefile ]  || \
 	    ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
 
@@ -448,15 +454,29 @@
 	regress/unittests/sshbuf/test_sshbuf_fixed.o
 
 regress/unittests/sshbuf/test_sshbuf$(EXEEXT): ${UNITTESTS_TEST_SSHBUF_OBJS} \
-    regress/unittests/test_helper/libtest_helper.a
+    regress/unittests/test_helper/libtest_helper.a libssh.a
 	$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHBUF_OBJS) \
 	    -L regress/unittests/test_helper -ltest_helper \
 	    -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
 
+UNITTESTS_TEST_SSHKEY_OBJS=\
+	regress/unittests/sshkey/test_fuzz.o \
+	regress/unittests/sshkey/tests.o \
+	regress/unittests/sshkey/common.o \
+	regress/unittests/sshkey/test_file.o \
+	regress/unittests/sshkey/test_sshkey.o
+
+regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \
+    regress/unittests/test_helper/libtest_helper.a libssh.a
+	$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHKEY_OBJS) \
+	    -L regress/unittests/test_helper -ltest_helper \
+	    -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+
 REGRESS_BINARIES=\
 	regress/modpipe$(EXEEXT) \
 	regress/setuid-allowed$(EXEEXT) \
-	regress/unittests/sshbuf/test_sshbuf$(EXEEXT)
+	regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \
+	regress/unittests/sshkey/test_sshkey$(EXEEXT)
 
 tests interop-tests: regress-prep $(TARGETS) $(REGRESS_BINARIES)
 	BUILDDIR=`pwd`; \
diff --git a/regress/Makefile b/regress/Makefile
index 370f28a..09ceee7 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -1,4 +1,4 @@
-#	$OpenBSD: Makefile,v 1.69 2014/04/30 05:32:00 djm Exp $
+#	$OpenBSD: Makefile,v 1.70 2014/06/24 01:14:17 djm Exp $
 
 REGRESS_TARGETS=	unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t-exec
 tests:		$(REGRESS_TARGETS)
@@ -102,9 +102,6 @@
 
 CPPFLAGS=-I..
 
-unit:
-	(set -e ; cd ${.CURDIR}/unittests ; make)
-
 t1:
 	${TEST_SSH_SSHKEYGEN} -if ${.CURDIR}/rsa_ssh2.prv | diff - ${.CURDIR}/rsa_openssh.prv
 	tr '\n' '\r' <${.CURDIR}/rsa_ssh2.prv > ${.OBJDIR}/rsa_ssh2_cr.prv
@@ -186,4 +183,7 @@
 
 # Unit tests, built by top-level Makefile
 unit:
-	${.OBJDIR}/unittests/sshbuf/test_sshbuf
+	set -e ; if test -z "${SKIP_UNIT}" ; then \
+		${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
+		${.OBJDIR}/unittests/sshkey/test_sshkey ; \
+	fi
diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile
index 2581a58..bdb4574 100644
--- a/regress/unittests/Makefile
+++ b/regress/unittests/Makefile
@@ -1,5 +1,5 @@
 #	$OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $
 
-SUBDIR=	test_helper sshbuf
+SUBDIR=	test_helper sshbuf sshkey
 
 .include <bsd.subdir.mk>
diff --git a/regress/unittests/sshkey/Makefile b/regress/unittests/sshkey/Makefile
new file mode 100644
index 0000000..1bcd266
--- /dev/null
+++ b/regress/unittests/sshkey/Makefile
@@ -0,0 +1,13 @@
+#	$OpenBSD: Makefile,v 1.1 2014/06/24 01:14:18 djm Exp $
+
+TEST_ENV=      "MALLOC_OPTIONS=AFGJPRX"
+
+PROG=test_sshkey
+SRCS=tests.c test_sshkey.c test_file.c test_fuzz.c common.c
+REGRESS_TARGETS=run-regress-${PROG}
+
+run-regress-${PROG}: ${PROG}
+	env ${TEST_ENV} ./${PROG} -d ${.CURDIR}/testdata
+
+.include <bsd.regress.mk>
+
diff --git a/regress/unittests/sshkey/common.c b/regress/unittests/sshkey/common.c
new file mode 100644
index 0000000..b73a788
--- /dev/null
+++ b/regress/unittests/sshkey/common.c
@@ -0,0 +1,80 @@
+/* 	$OpenBSD: common.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
+/*
+ * Helpers for key API tests
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/objects.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "ssherr.h"
+#include "authfile.h"
+#include "sshkey.h"
+#include "sshbuf.h"
+
+#include "common.h"
+
+struct sshbuf *
+load_file(const char *name)
+{
+	int fd;
+	struct sshbuf *ret;
+
+	ASSERT_PTR_NE(ret = sshbuf_new(), NULL);
+	ASSERT_INT_NE(fd = open(test_data_file(name), O_RDONLY), -1);
+	ASSERT_INT_EQ(sshkey_load_file(fd, name, ret), 0);
+	close(fd);
+	return ret;
+}
+
+struct sshbuf *
+load_text_file(const char *name)
+{
+	struct sshbuf *ret = load_file(name);
+	const u_char *p;
+
+	/* Trim whitespace at EOL */
+	for (p = sshbuf_ptr(ret); sshbuf_len(ret) > 0;) {
+		if (p[sshbuf_len(ret) - 1] == '\r' ||
+		    p[sshbuf_len(ret) - 1] == '\t' ||
+		    p[sshbuf_len(ret) - 1] == ' ' ||
+		    p[sshbuf_len(ret) - 1] == '\n')
+			ASSERT_INT_EQ(sshbuf_consume_end(ret, 1), 0);
+		else
+			break;
+	}
+	/* \0 terminate */
+	ASSERT_INT_EQ(sshbuf_put_u8(ret, 0), 0);
+	return ret;
+}
+
+BIGNUM *
+load_bignum(const char *name)
+{
+	BIGNUM *ret = NULL;
+	struct sshbuf *buf;
+
+	buf = load_text_file(name);
+	ASSERT_INT_NE(BN_hex2bn(&ret, (const char *)sshbuf_ptr(buf)), 0);
+	sshbuf_free(buf);
+	return ret;
+}
+
diff --git a/regress/unittests/sshkey/common.h b/regress/unittests/sshkey/common.h
new file mode 100644
index 0000000..bf7d19d
--- /dev/null
+++ b/regress/unittests/sshkey/common.h
@@ -0,0 +1,16 @@
+/* 	$OpenBSD: common.h,v 1.1 2014/06/24 01:14:18 djm Exp $ */
+/*
+ * Helpers for key API tests
+ *
+ * Placed in the public domain
+ */
+
+/* Load a binary file into a buffer */
+struct sshbuf *load_file(const char *name);
+
+/* Load a text file into a buffer */
+struct sshbuf *load_text_file(const char *name);
+
+/* Load a bignum from a file */
+BIGNUM *load_bignum(const char *name);
+
diff --git a/regress/unittests/sshkey/mktestdata.sh b/regress/unittests/sshkey/mktestdata.sh
new file mode 100755
index 0000000..2039bf9
--- /dev/null
+++ b/regress/unittests/sshkey/mktestdata.sh
@@ -0,0 +1,189 @@
+#!/bin/sh
+
+PW=mekmitasdigoat
+
+rsa1_params() {
+	_in="$1"
+	_outbase="$2"
+	set -e
+	ssh-keygen -f $_in -e -m pkcs8 | \
+	    openssl rsa -noout -text -pubin | \
+	    awk '/^Modulus:$/,/^Exponent:/' | \
+	    grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.n
+	# XXX need conversion support in ssh-keygen for the other params
+	for x in n ; do
+		echo "" >> ${_outbase}.$x
+		echo ============ ${_outbase}.$x
+		cat ${_outbase}.$x
+		echo ============
+	done
+}
+
+rsa_params() {
+	_in="$1"
+	_outbase="$2"
+	set -e
+	openssl rsa -noout -text -in $_in | \
+	    awk '/^modulus:$/,/^publicExponent:/' | \
+	    grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.n
+	openssl rsa -noout -text -in $_in | \
+	    awk '/^prime1:$/,/^prime2:/' | \
+	    grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.p
+	openssl rsa -noout -text -in $_in | \
+	    awk '/^prime2:$/,/^exponent1:/' | \
+	    grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.q
+	for x in n p q ; do
+		echo "" >> ${_outbase}.$x
+		echo ============ ${_outbase}.$x
+		cat ${_outbase}.$x
+		echo ============
+	done
+}
+
+dsa_params() {
+	_in="$1"
+	_outbase="$2"
+	set -e
+	openssl dsa -noout -text -in $_in | \
+	    awk '/^priv:$/,/^pub:/' | \
+	    grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.priv
+	openssl dsa -noout -text -in $_in | \
+	    awk '/^pub:/,/^P:/' | #\
+	    grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.pub
+	openssl dsa -noout -text -in $_in | \
+	    awk '/^G:/,0' | \
+	    grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.g
+	for x in priv pub g ; do
+		echo "" >> ${_outbase}.$x
+		echo ============ ${_outbase}.$x
+		cat ${_outbase}.$x
+		echo ============
+	done
+}
+
+ecdsa_params() {
+	_in="$1"
+	_outbase="$2"
+	set -e
+	openssl ec -noout -text -in $_in | \
+	    awk '/^priv:$/,/^pub:/' | \
+	    grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.priv
+	openssl ec -noout -text -in $_in | \
+	    awk '/^pub:/,/^ASN1 OID:/' | #\
+	    grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.pub
+	openssl ec -noout -text -in $_in | \
+	    grep "ASN1 OID:" | tr -d '\n' | \
+	    sed 's/.*: //;s/ *$//' > ${_outbase}.curve
+	for x in priv pub curve ; do
+		echo "" >> ${_outbase}.$x
+		echo ============ ${_outbase}.$x
+		cat ${_outbase}.$x
+		echo ============
+	done
+}
+
+set -ex
+
+cd testdata
+
+rm -f rsa1_1 rsa_1 dsa_1 ecdsa_1 ed25519_1
+rm -f rsa1_2 rsa_2 dsa_2 ecdsa_2 ed25519_2
+rm -f rsa_n dsa_n ecdsa_n # new-format keys
+rm -f rsa1_1_pw rsa_1_pw dsa_1_pw ecdsa_1_pw ed25519_1_pw
+rm -f rsa_n_pw dsa_n_pw ecdsa_n_pw
+rm -f pw *.pub *.bn.* *.param.* *.fp *.fp.bb
+
+ssh-keygen -t rsa1 -b 768 -C "RSA1 test key #1" -N "" -f rsa1_1
+ssh-keygen -t rsa -b 768 -C "RSA test key #1" -N "" -f rsa_1
+ssh-keygen -t dsa -b 1024 -C "DSA test key #1" -N "" -f dsa_1
+ssh-keygen -t ecdsa -b 256 -C "ECDSA test key #1" -N "" -f ecdsa_1
+ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_1
+
+ssh-keygen -t rsa1 -b 2048 -C "RSA1 test key #2" -N "" -f rsa1_2
+ssh-keygen -t rsa -b 2048 -C "RSA test key #2" -N "" -f rsa_2
+ssh-keygen -t dsa -b 1024 -C "DSA test key #2" -N "" -f dsa_2
+ssh-keygen -t ecdsa -b 521 -C "ECDSA test key #2" -N "" -f ecdsa_2
+ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_2
+
+cp rsa_1 rsa_n
+cp dsa_1 dsa_n
+cp ecdsa_1 ecdsa_n
+
+cp rsa1_1 rsa1_1_pw
+cp rsa_1 rsa_1_pw
+cp dsa_1 dsa_1_pw
+cp ecdsa_1 ecdsa_1_pw
+cp ed25519_1 ed25519_1_pw
+cp rsa_1 rsa_n_pw
+cp dsa_1 dsa_n_pw
+cp ecdsa_1 ecdsa_n_pw
+
+ssh-keygen -pf rsa1_1_pw -N "$PW"
+ssh-keygen -pf rsa_1_pw -N "$PW"
+ssh-keygen -pf dsa_1_pw -N "$PW"
+ssh-keygen -pf ecdsa_1_pw -N "$PW"
+ssh-keygen -pf ed25519_1_pw -N "$PW"
+ssh-keygen -opf rsa_n_pw -N "$PW"
+ssh-keygen -opf dsa_n_pw -N "$PW"
+ssh-keygen -opf ecdsa_n_pw -N "$PW"
+
+rsa1_params rsa1_1 rsa1_1.param
+rsa1_params rsa1_2 rsa1_2.param
+rsa_params rsa_1 rsa_1.param
+rsa_params rsa_2 rsa_2.param
+dsa_params dsa_1 dsa_1.param
+dsa_params dsa_1 dsa_1.param
+ecdsa_params ecdsa_1 ecdsa_1.param
+ecdsa_params ecdsa_2 ecdsa_2.param
+# XXX ed25519 params
+
+ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
+    -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
+    -V 19990101:20110101 -z 1 rsa_1.pub
+ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
+    -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
+    -V 19990101:20110101 -z 2 dsa_1.pub
+ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
+    -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
+    -V 19990101:20110101 -z 3 ecdsa_1.pub
+ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
+    -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
+    -V 19990101:20110101 -z 4 ed25519_1.pub
+
+ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \
+    -V 19990101:20110101 -z 5 rsa_1.pub
+ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \
+    -V 19990101:20110101 -z 6 dsa_1.pub
+ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \
+    -V 19990101:20110101 -z 7 ecdsa_1.pub
+ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \
+    -V 19990101:20110101 -z 8 ed25519_1.pub
+
+ssh-keygen -lf rsa1_1 | awk '{print $2}' > rsa1_1.fp
+ssh-keygen -lf rsa_1 | awk '{print $2}' > rsa_1.fp
+ssh-keygen -lf dsa_1 | awk '{print $2}' > dsa_1.fp
+ssh-keygen -lf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp
+ssh-keygen -lf ed25519_1 | awk '{print $2}' > ed25519_1.fp
+ssh-keygen -lf rsa1_2 | awk '{print $2}' > rsa1_2.fp
+ssh-keygen -lf rsa_2 | awk '{print $2}' > rsa_2.fp
+ssh-keygen -lf dsa_2 | awk '{print $2}' > dsa_2.fp
+ssh-keygen -lf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp
+ssh-keygen -lf ed25519_2 | awk '{print $2}' > ed25519_2.fp
+
+ssh-keygen -lf dsa_1-cert.pub  | awk '{print $2}' > dsa_1-cert.fp
+ssh-keygen -lf ecdsa_1-cert.pub  | awk '{print $2}' > ecdsa_1-cert.fp
+ssh-keygen -lf ed25519_1-cert.pub  | awk '{print $2}' > ed25519_1-cert.fp
+ssh-keygen -lf rsa_1-cert.pub  | awk '{print $2}' > rsa_1-cert.fp
+
+ssh-keygen -Bf rsa1_1 | awk '{print $2}' > rsa1_1.fp.bb
+ssh-keygen -Bf rsa_1 | awk '{print $2}' > rsa_1.fp.bb
+ssh-keygen -Bf dsa_1 | awk '{print $2}' > dsa_1.fp.bb
+ssh-keygen -Bf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp.bb
+ssh-keygen -Bf ed25519_1 | awk '{print $2}' > ed25519_1.fp.bb
+ssh-keygen -Bf rsa1_2 | awk '{print $2}' > rsa1_2.fp.bb
+ssh-keygen -Bf rsa_2 | awk '{print $2}' > rsa_2.fp.bb
+ssh-keygen -Bf dsa_2 | awk '{print $2}' > dsa_2.fp.bb
+ssh-keygen -Bf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp.bb
+ssh-keygen -Bf ed25519_2 | awk '{print $2}' > ed25519_2.fp.bb
+
+echo "$PW" > pw
diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c
new file mode 100644
index 0000000..3c84f15
--- /dev/null
+++ b/regress/unittests/sshkey/test_file.c
@@ -0,0 +1,451 @@
+/* 	$OpenBSD: test_file.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
+/*
+ * Regress test for sshkey.h key management API
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/objects.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "ssherr.h"
+#include "authfile.h"
+#include "sshkey.h"
+#include "sshbuf.h"
+
+#include "common.h"
+
+void sshkey_file_tests(void);
+
+void
+sshkey_file_tests(void)
+{
+	struct sshkey *k1, *k2;
+	struct sshbuf *buf, *pw;
+	BIGNUM *a, *b, *c;
+	char *cp;
+
+	TEST_START("load passphrase");
+	pw = load_text_file("pw");
+	TEST_DONE();
+
+	TEST_START("parse RSA1 from private");
+	buf = load_file("rsa1_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "rsa1_1",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k1, NULL);
+	a = load_bignum("rsa1_1.param.n");
+	ASSERT_BIGNUM_EQ(k1->rsa->n, a);
+	BN_free(a);
+	TEST_DONE();
+
+	TEST_START("parse RSA1 from private w/ passphrase");
+	buf = load_file("rsa1_1_pw");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    (const char *)sshbuf_ptr(pw), "rsa1_1_pw", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("load RSA1 from public");
+	ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa1_1.pub"), &k2,
+	    NULL), 0);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("RSA1 key hex fingerprint");
+	buf = load_text_file("rsa1_1.fp");
+	cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	TEST_START("RSA1 key bubblebabble fingerprint");
+	buf = load_text_file("rsa1_1.fp.bb");
+	cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	sshkey_free(k1);
+
+	TEST_START("parse RSA from private");
+	buf = load_file("rsa_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "rsa_1",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k1, NULL);
+	a = load_bignum("rsa_1.param.n");
+	b = load_bignum("rsa_1.param.p");
+	c = load_bignum("rsa_1.param.q");
+	ASSERT_BIGNUM_EQ(k1->rsa->n, a);
+	ASSERT_BIGNUM_EQ(k1->rsa->p, b);
+	ASSERT_BIGNUM_EQ(k1->rsa->q, c);
+	BN_free(a);
+	BN_free(b);
+	BN_free(c);
+	TEST_DONE();
+
+	TEST_START("parse RSA from private w/ passphrase");
+	buf = load_file("rsa_1_pw");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    (const char *)sshbuf_ptr(pw), "rsa_1_pw", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("parse RSA from new-format");
+	buf = load_file("rsa_n");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    "", "rsa_n", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("parse RSA from new-format w/ passphrase");
+	buf = load_file("rsa_n_pw");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    (const char *)sshbuf_ptr(pw), "rsa_n_pw", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("load RSA from public");
+	ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2,
+	    NULL), 0);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("load RSA cert");
+	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k2), 0);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(k2->type, KEY_RSA_CERT);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
+	ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
+	TEST_DONE();
+
+	TEST_START("RSA key hex fingerprint");
+	buf = load_text_file("rsa_1.fp");
+	cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	TEST_START("RSA cert hex fingerprint");
+	buf = load_text_file("rsa_1-cert.fp");
+	cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("RSA key bubblebabble fingerprint");
+	buf = load_text_file("rsa_1.fp.bb");
+	cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	sshkey_free(k1);
+
+	TEST_START("parse DSA from private");
+	buf = load_file("dsa_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "dsa_1",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k1, NULL);
+	a = load_bignum("dsa_1.param.g");
+	b = load_bignum("dsa_1.param.priv");
+	c = load_bignum("dsa_1.param.pub");
+	ASSERT_BIGNUM_EQ(k1->dsa->g, a);
+	ASSERT_BIGNUM_EQ(k1->dsa->priv_key, b);
+	ASSERT_BIGNUM_EQ(k1->dsa->pub_key, c);
+	BN_free(a);
+	BN_free(b);
+	BN_free(c);
+	TEST_DONE();
+
+	TEST_START("parse DSA from private w/ passphrase");
+	buf = load_file("dsa_1_pw");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    (const char *)sshbuf_ptr(pw), "dsa_1_pw", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("parse DSA from new-format");
+	buf = load_file("dsa_n");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    "", "dsa_n", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("parse DSA from new-format w/ passphrase");
+	buf = load_file("dsa_n_pw");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    (const char *)sshbuf_ptr(pw), "dsa_n_pw", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("load DSA from public");
+	ASSERT_INT_EQ(sshkey_load_public(test_data_file("dsa_1.pub"), &k2,
+	    NULL), 0);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("load DSA cert");
+	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k2), 0);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(k2->type, KEY_DSA_CERT);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
+	ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
+	TEST_DONE();
+
+	TEST_START("DSA key hex fingerprint");
+	buf = load_text_file("dsa_1.fp");
+	cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	TEST_START("DSA cert hex fingerprint");
+	buf = load_text_file("dsa_1-cert.fp");
+	cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("DSA key bubblebabble fingerprint");
+	buf = load_text_file("dsa_1.fp.bb");
+	cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	sshkey_free(k1);
+
+	TEST_START("parse ECDSA from private");
+	buf = load_file("ecdsa_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "ecdsa_1",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k1, NULL);
+	buf = load_text_file("ecdsa_1.param.curve");
+	ASSERT_STRING_EQ((const char *)sshbuf_ptr(buf),
+	    OBJ_nid2sn(k1->ecdsa_nid));
+	sshbuf_free(buf);
+	a = load_bignum("ecdsa_1.param.priv");
+	b = load_bignum("ecdsa_1.param.pub");
+	c = EC_POINT_point2bn(EC_KEY_get0_group(k1->ecdsa),
+	    EC_KEY_get0_public_key(k1->ecdsa), POINT_CONVERSION_UNCOMPRESSED,
+	    NULL, NULL);
+	ASSERT_PTR_NE(c, NULL);
+	ASSERT_BIGNUM_EQ(EC_KEY_get0_private_key(k1->ecdsa), a);
+	ASSERT_BIGNUM_EQ(b, c);
+	BN_free(a);
+	BN_free(b);
+	BN_free(c);
+	TEST_DONE();
+
+	TEST_START("parse ECDSA from private w/ passphrase");
+	buf = load_file("ecdsa_1_pw");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    (const char *)sshbuf_ptr(pw), "ecdsa_1_pw", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("parse ECDSA from new-format");
+	buf = load_file("ecdsa_n");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    "", "ecdsa_n", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("parse ECDSA from new-format w/ passphrase");
+	buf = load_file("ecdsa_n_pw");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    (const char *)sshbuf_ptr(pw), "ecdsa_n_pw", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("load ECDSA from public");
+	ASSERT_INT_EQ(sshkey_load_public(test_data_file("ecdsa_1.pub"), &k2,
+	    NULL), 0);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("load ECDSA cert");
+	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_1"), &k2), 0);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(k2->type, KEY_ECDSA_CERT);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
+	ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
+	TEST_DONE();
+
+	TEST_START("ECDSA key hex fingerprint");
+	buf = load_text_file("ecdsa_1.fp");
+	cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	TEST_START("ECDSA cert hex fingerprint");
+	buf = load_text_file("ecdsa_1-cert.fp");
+	cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("ECDSA key bubblebabble fingerprint");
+	buf = load_text_file("ecdsa_1.fp.bb");
+	cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	sshkey_free(k1);
+
+	TEST_START("parse Ed25519 from private");
+	buf = load_file("ed25519_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "ed25519_1",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_INT_EQ(k1->type, KEY_ED25519);
+	/* XXX check key contents */
+	TEST_DONE();
+
+	TEST_START("parse Ed25519 from private w/ passphrase");
+	buf = load_file("ed25519_1_pw");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+	    (const char *)sshbuf_ptr(pw), "ed25519_1_pw", &k2, NULL), 0);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("load Ed25519 from public");
+	ASSERT_INT_EQ(sshkey_load_public(test_data_file("ed25519_1.pub"), &k2,
+	    NULL), 0);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("load Ed25519 cert");
+	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_1"), &k2), 0);
+	ASSERT_PTR_NE(k2, NULL);
+	ASSERT_INT_EQ(k2->type, KEY_ED25519_CERT);
+	ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
+	ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
+	TEST_DONE();
+
+	TEST_START("Ed25519 key hex fingerprint");
+	buf = load_text_file("ed25519_1.fp");
+	cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	TEST_START("Ed25519 cert hex fingerprint");
+	buf = load_text_file("ed25519_1-cert.fp");
+	cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	sshkey_free(k2);
+	TEST_DONE();
+
+	TEST_START("Ed25519 key bubblebabble fingerprint");
+	buf = load_text_file("ed25519_1.fp.bb");
+	cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
+	ASSERT_PTR_NE(cp, NULL);
+	ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+	sshbuf_free(buf);
+	free(cp);
+	TEST_DONE();
+
+	sshkey_free(k1);
+
+	sshbuf_free(pw);
+
+}
diff --git a/regress/unittests/sshkey/test_fuzz.c b/regress/unittests/sshkey/test_fuzz.c
new file mode 100644
index 0000000..be309f5
--- /dev/null
+++ b/regress/unittests/sshkey/test_fuzz.c
@@ -0,0 +1,396 @@
+/* 	$OpenBSD: test_fuzz.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
+/*
+ * Fuzz tests for key parsing
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/objects.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "ssherr.h"
+#include "authfile.h"
+#include "sshkey.h"
+#include "sshbuf.h"
+
+#include "common.h"
+
+void sshkey_fuzz_tests(void);
+
+static void
+onerror(void *fuzz)
+{
+	fprintf(stderr, "Failed during fuzz:\n");
+	fuzz_dump((struct fuzz *)fuzz);
+}
+
+static void
+public_fuzz(struct sshkey *k)
+{
+	struct sshkey *k1;
+	struct sshbuf *buf;
+	struct fuzz *fuzz;
+
+	ASSERT_PTR_NE(buf = sshbuf_new(), NULL);
+	ASSERT_INT_EQ(sshkey_to_blob_buf(k, buf), 0);
+	/* XXX need a way to run the tests in "slow, but complete" mode */
+	fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | /* XXX too slow FUZZ_2_BIT_FLIP | */
+	    FUZZ_1_BYTE_FLIP | /* XXX too slow FUZZ_2_BYTE_FLIP | */
+	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END,
+	    sshbuf_mutable_ptr(buf), sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(buf), sshbuf_len(buf),
+	    &k1), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		if (sshkey_from_blob(fuzz_ptr(fuzz), fuzz_len(fuzz), &k1) == 0)
+			sshkey_free(k1);
+	}
+	fuzz_cleanup(fuzz);
+}
+
+static void
+sig_fuzz(struct sshkey *k)
+{
+	struct fuzz *fuzz;
+	u_char *sig, c[] = "some junk to be signed";
+	size_t l;
+
+	ASSERT_INT_EQ(sshkey_sign(k, &sig, &l, c, sizeof(c), 0), 0);
+	ASSERT_SIZE_T_GT(l, 0);
+	fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | /* too slow FUZZ_2_BIT_FLIP | */
+	    FUZZ_1_BYTE_FLIP | FUZZ_2_BYTE_FLIP |
+	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END, sig, l);
+	ASSERT_INT_EQ(sshkey_verify(k, sig, l, c, sizeof(c), 0), 0);
+	free(sig);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		sshkey_verify(k, fuzz_ptr(fuzz), fuzz_len(fuzz),
+		    c, sizeof(c), 0);
+	}
+	fuzz_cleanup(fuzz);
+}
+
+void
+sshkey_fuzz_tests(void)
+{
+	struct sshkey *k1;
+	struct sshbuf *buf, *fuzzed;
+	struct fuzz *fuzz;
+	int r;
+
+	TEST_START("fuzz RSA1 private");
+	buf = load_file("rsa1_1");
+	fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP |
+	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END,
+	    sshbuf_mutable_ptr(buf), sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
+		ASSERT_INT_EQ(r, 0);
+		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
+		    &k1, NULL) == 0)
+			sshkey_free(k1);
+		sshbuf_reset(fuzzed);
+	}
+	sshbuf_free(fuzzed);
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+
+	TEST_START("fuzz RSA1 public");
+	buf = load_file("rsa1_1_pw");
+	fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP |
+	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END,
+	    sshbuf_mutable_ptr(buf), sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_parse_public_rsa1_fileblob(buf, &k1, NULL), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
+		ASSERT_INT_EQ(r, 0);
+		if (sshkey_parse_public_rsa1_fileblob(fuzzed, &k1, NULL) == 0)
+			sshkey_free(k1);
+		sshbuf_reset(fuzzed);
+	}
+	sshbuf_free(fuzzed);
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+
+	TEST_START("fuzz RSA private");
+	buf = load_file("rsa_1");
+	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
+	    sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
+		ASSERT_INT_EQ(r, 0);
+		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
+		    &k1, NULL) == 0)
+			sshkey_free(k1);
+		sshbuf_reset(fuzzed);
+	}
+	sshbuf_free(fuzzed);
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+
+	TEST_START("fuzz RSA new-format private");
+	buf = load_file("rsa_n");
+	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
+	    sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
+		ASSERT_INT_EQ(r, 0);
+		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
+		    &k1, NULL) == 0)
+			sshkey_free(k1);
+		sshbuf_reset(fuzzed);
+	}
+	sshbuf_free(fuzzed);
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+
+	TEST_START("fuzz DSA private");
+	buf = load_file("dsa_1");
+	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
+	    sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
+		ASSERT_INT_EQ(r, 0);
+		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
+		    &k1, NULL) == 0)
+			sshkey_free(k1);
+		sshbuf_reset(fuzzed);
+	}
+	sshbuf_free(fuzzed);
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+
+	TEST_START("fuzz DSA new-format private");
+	buf = load_file("dsa_n");
+	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
+	    sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
+		ASSERT_INT_EQ(r, 0);
+		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
+		    &k1, NULL) == 0)
+			sshkey_free(k1);
+		sshbuf_reset(fuzzed);
+	}
+	sshbuf_free(fuzzed);
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+
+	TEST_START("fuzz ECDSA private");
+	buf = load_file("ecdsa_1");
+	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
+	    sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
+		ASSERT_INT_EQ(r, 0);
+		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
+		    &k1, NULL) == 0)
+			sshkey_free(k1);
+		sshbuf_reset(fuzzed);
+	}
+	sshbuf_free(fuzzed);
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+
+	TEST_START("fuzz ECDSA new-format private");
+	buf = load_file("ecdsa_n");
+	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
+	    sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
+		ASSERT_INT_EQ(r, 0);
+		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
+		    &k1, NULL) == 0)
+			sshkey_free(k1);
+		sshbuf_reset(fuzzed);
+	}
+	sshbuf_free(fuzzed);
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+
+	TEST_START("fuzz Ed25519 private");
+	buf = load_file("ed25519_1");
+	fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
+	    sshbuf_len(buf));
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshkey_free(k1);
+	sshbuf_free(buf);
+	ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
+	TEST_ONERROR(onerror, fuzz);
+	for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
+		r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
+		ASSERT_INT_EQ(r, 0);
+		if (sshkey_parse_private_fileblob(fuzzed, "", "key",
+		    &k1, NULL) == 0)
+			sshkey_free(k1);
+		sshbuf_reset(fuzzed);
+	}
+	sshbuf_free(fuzzed);
+	fuzz_cleanup(fuzz);
+	TEST_DONE();
+
+	TEST_START("fuzz RSA public");
+	buf = load_file("rsa_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	public_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz RSA cert");
+	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0);
+	public_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz DSA public");
+	buf = load_file("dsa_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	public_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz DSA cert");
+	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k1), 0);
+	public_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz ECDSA public");
+	buf = load_file("ecdsa_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	public_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz ECDSA cert");
+	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_1"), &k1), 0);
+	public_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz Ed25519 public");
+	buf = load_file("ed25519_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	public_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz Ed25519 cert");
+	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_1"), &k1), 0);
+	public_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz RSA sig");
+	buf = load_file("rsa_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	sig_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz DSA sig");
+	buf = load_file("dsa_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	sig_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz ECDSA sig");
+	buf = load_file("ecdsa_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	sig_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("fuzz Ed25519 sig");
+	buf = load_file("ed25519_1");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
+	    &k1, NULL), 0);
+	sshbuf_free(buf);
+	sig_fuzz(k1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+/* XXX fuzz decoded new-format blobs too */
+
+}
diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c
new file mode 100644
index 0000000..2d69b4d
--- /dev/null
+++ b/regress/unittests/sshkey/test_sshkey.c
@@ -0,0 +1,343 @@
+/* 	$OpenBSD: test_sshkey.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
+/*
+ * Regress test for sshkey.h key management API
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#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/rsa.h>
+#include <openssl/dsa.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "ssherr.h"
+#include "sshbuf.h"
+#define SSHBUF_INTERNAL 1	/* access internals for testing */
+#include "sshkey.h"
+
+#include "authfile.h"
+#include "common.h"
+#include "ssh2.h"
+
+void sshkey_tests(void);
+
+static void
+build_cert(struct sshbuf *b, const struct sshkey *k, const char *type,
+    const struct sshkey *sign_key, const struct sshkey *ca_key)
+{
+	struct sshbuf *ca_buf, *pk, *principals, *critopts, *exts;
+	u_char *sigblob;
+	size_t siglen;
+
+	ca_buf = sshbuf_new();
+	ASSERT_INT_EQ(sshkey_to_blob_buf(ca_key, ca_buf), 0);
+
+	/*
+	 * Get the public key serialisation by rendering the key and skipping
+	 * the type string. This is a bit of a hack :/
+	 */
+	pk = sshbuf_new();
+	ASSERT_INT_EQ(sshkey_plain_to_blob_buf(k, pk), 0);
+	ASSERT_INT_EQ(sshbuf_skip_string(pk), 0);
+
+	principals = sshbuf_new();
+	ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gsamsa"), 0);
+	ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gregor"), 0);
+
+	critopts = sshbuf_new();
+	/* XXX fill this in */
+
+	exts = sshbuf_new();
+	/* XXX fill this in */
+
+	ASSERT_INT_EQ(sshbuf_put_cstring(b, type), 0);
+	ASSERT_INT_EQ(sshbuf_put_cstring(b, "noncenoncenonce!"), 0); /* nonce */
+	ASSERT_INT_EQ(sshbuf_putb(b, pk), 0); /* public key serialisation */
+	ASSERT_INT_EQ(sshbuf_put_u64(b, 1234), 0); /* serial */
+	ASSERT_INT_EQ(sshbuf_put_u32(b, SSH2_CERT_TYPE_USER), 0); /* type */
+	ASSERT_INT_EQ(sshbuf_put_cstring(b, "gregor"), 0); /* key ID */
+	ASSERT_INT_EQ(sshbuf_put_stringb(b, principals), 0); /* principals */
+	ASSERT_INT_EQ(sshbuf_put_u64(b, 0), 0); /* start */
+	ASSERT_INT_EQ(sshbuf_put_u64(b, 0xffffffffffffffffULL), 0); /* end */
+	ASSERT_INT_EQ(sshbuf_put_stringb(b, critopts), 0); /* options */
+	ASSERT_INT_EQ(sshbuf_put_stringb(b, exts), 0); /* extensions */
+	ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */
+	ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */
+	ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen,
+	    sshbuf_ptr(b), sshbuf_len(b), 0), 0);
+	ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */
+
+	free(sigblob);
+	sshbuf_free(ca_buf);
+	sshbuf_free(exts);
+	sshbuf_free(critopts);
+	sshbuf_free(principals);
+	sshbuf_free(pk);
+}
+
+void
+sshkey_tests(void)
+{
+	struct sshkey *k1, *k2, *k3, *k4, *kr, *kd, *ke, *kf;
+	struct sshbuf *b;
+
+	TEST_START("new invalid");
+	k1 = sshkey_new(-42);
+	ASSERT_PTR_EQ(k1, NULL);
+	TEST_DONE();
+
+	TEST_START("new/free KEY_UNSPEC");
+	k1 = sshkey_new(KEY_UNSPEC);
+	ASSERT_PTR_NE(k1, NULL);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("new/free KEY_RSA1");
+	k1 = sshkey_new(KEY_RSA1);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_NE(k1->rsa, NULL);
+	ASSERT_PTR_NE(k1->rsa->n, NULL);
+	ASSERT_PTR_NE(k1->rsa->e, NULL);
+	ASSERT_PTR_EQ(k1->rsa->p, NULL);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("new/free KEY_RSA");
+	k1 = sshkey_new(KEY_RSA);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_NE(k1->rsa, NULL);
+	ASSERT_PTR_NE(k1->rsa->n, NULL);
+	ASSERT_PTR_NE(k1->rsa->e, NULL);
+	ASSERT_PTR_EQ(k1->rsa->p, NULL);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("new/free KEY_DSA");
+	k1 = sshkey_new(KEY_DSA);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_NE(k1->dsa, NULL);
+	ASSERT_PTR_NE(k1->dsa->g, NULL);
+	ASSERT_PTR_EQ(k1->dsa->priv_key, NULL);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("new/free KEY_ECDSA");
+	k1 = sshkey_new(KEY_ECDSA);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_EQ(k1->ecdsa, NULL);  /* Can't allocate without NID */
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("new/free KEY_ED25519");
+	k1 = sshkey_new(KEY_ED25519);
+	ASSERT_PTR_NE(k1, NULL);
+	/* These should be blank until key loaded or generated */
+	ASSERT_PTR_EQ(k1->ed25519_sk, NULL);
+	ASSERT_PTR_EQ(k1->ed25519_pk, NULL);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("new_private KEY_RSA");
+	k1 = sshkey_new_private(KEY_RSA);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_NE(k1->rsa, NULL);
+	ASSERT_PTR_NE(k1->rsa->n, NULL);
+	ASSERT_PTR_NE(k1->rsa->e, NULL);
+	ASSERT_PTR_NE(k1->rsa->p, NULL);
+	ASSERT_INT_EQ(sshkey_add_private(k1), 0);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("new_private KEY_DSA");
+	k1 = sshkey_new_private(KEY_DSA);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_NE(k1->dsa, NULL);
+	ASSERT_PTR_NE(k1->dsa->g, NULL);
+	ASSERT_PTR_NE(k1->dsa->priv_key, NULL);
+	ASSERT_INT_EQ(sshkey_add_private(k1), 0);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("generate KEY_RSA too small modulus");
+	ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 128, &k1),
+	    SSH_ERR_INVALID_ARGUMENT);
+	ASSERT_PTR_EQ(k1, NULL);
+	TEST_DONE();
+
+	TEST_START("generate KEY_RSA too large modulus");
+	ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1 << 20, &k1),
+	    SSH_ERR_INVALID_ARGUMENT);
+	ASSERT_PTR_EQ(k1, NULL);
+	TEST_DONE();
+
+	TEST_START("generate KEY_DSA wrong bits");
+	ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 2048, &k1),
+	    SSH_ERR_INVALID_ARGUMENT);
+	ASSERT_PTR_EQ(k1, NULL);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("generate KEY_ECDSA wrong bits");
+	ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 42, &k1),
+	    SSH_ERR_INVALID_ARGUMENT);
+	ASSERT_PTR_EQ(k1, NULL);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("generate KEY_RSA");
+	ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 768, &kr), 0);
+	ASSERT_PTR_NE(kr, NULL);
+	ASSERT_PTR_NE(kr->rsa, NULL);
+	ASSERT_PTR_NE(kr->rsa->n, NULL);
+	ASSERT_PTR_NE(kr->rsa->e, NULL);
+	ASSERT_PTR_NE(kr->rsa->p, NULL);
+	ASSERT_INT_EQ(BN_num_bits(kr->rsa->n), 768);
+	TEST_DONE();
+
+	TEST_START("generate KEY_DSA");
+	ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &kd), 0);
+	ASSERT_PTR_NE(kd, NULL);
+	ASSERT_PTR_NE(kd->dsa, NULL);
+	ASSERT_PTR_NE(kd->dsa->g, NULL);
+	ASSERT_PTR_NE(kd->dsa->priv_key, NULL);
+	TEST_DONE();
+
+	TEST_START("generate KEY_ECDSA");
+	ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &ke), 0);
+	ASSERT_PTR_NE(ke, NULL);
+	ASSERT_PTR_NE(ke->ecdsa, NULL);
+	ASSERT_PTR_NE(EC_KEY_get0_public_key(ke->ecdsa), NULL);
+	ASSERT_PTR_NE(EC_KEY_get0_private_key(ke->ecdsa), NULL);
+	TEST_DONE();
+
+	TEST_START("generate KEY_ED25519");
+	ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 256, &kf), 0);
+	ASSERT_PTR_NE(kf, NULL);
+	ASSERT_INT_EQ(kf->type, KEY_ED25519);
+	ASSERT_PTR_NE(kf->ed25519_pk, NULL);
+	ASSERT_PTR_NE(kf->ed25519_sk, NULL);
+	TEST_DONE();
+
+	TEST_START("demote KEY_RSA");
+	ASSERT_INT_EQ(sshkey_demote(kr, &k1), 0);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_NE(kr, k1);
+	ASSERT_INT_EQ(k1->type, KEY_RSA);
+	ASSERT_PTR_NE(k1->rsa, NULL);
+	ASSERT_PTR_NE(k1->rsa->n, NULL);
+	ASSERT_PTR_NE(k1->rsa->e, NULL);
+	ASSERT_PTR_EQ(k1->rsa->p, NULL);
+	TEST_DONE();
+
+	TEST_START("equal KEY_RSA/demoted KEY_RSA");
+	ASSERT_INT_EQ(sshkey_equal(kr, k1), 1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("demote KEY_DSA");
+	ASSERT_INT_EQ(sshkey_demote(kd, &k1), 0);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_NE(kd, k1);
+	ASSERT_INT_EQ(k1->type, KEY_DSA);
+	ASSERT_PTR_NE(k1->dsa, NULL);
+	ASSERT_PTR_NE(k1->dsa->g, NULL);
+	ASSERT_PTR_EQ(k1->dsa->priv_key, NULL);
+	TEST_DONE();
+
+	TEST_START("equal KEY_DSA/demoted KEY_DSA");
+	ASSERT_INT_EQ(sshkey_equal(kd, k1), 1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("demote KEY_ECDSA");
+	ASSERT_INT_EQ(sshkey_demote(ke, &k1), 0);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_NE(ke, k1);
+	ASSERT_INT_EQ(k1->type, KEY_ECDSA);
+	ASSERT_PTR_NE(k1->ecdsa, NULL);
+	ASSERT_INT_EQ(k1->ecdsa_nid, ke->ecdsa_nid);
+	ASSERT_PTR_NE(EC_KEY_get0_public_key(ke->ecdsa), NULL);
+	ASSERT_PTR_EQ(EC_KEY_get0_private_key(k1->ecdsa), NULL);
+	TEST_DONE();
+
+	TEST_START("equal KEY_ECDSA/demoted KEY_ECDSA");
+	ASSERT_INT_EQ(sshkey_equal(ke, k1), 1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("demote KEY_ED25519");
+	ASSERT_INT_EQ(sshkey_demote(kf, &k1), 0);
+	ASSERT_PTR_NE(k1, NULL);
+	ASSERT_PTR_NE(kf, k1);
+	ASSERT_INT_EQ(k1->type, KEY_ED25519);
+	ASSERT_PTR_NE(k1->ed25519_pk, NULL);
+	ASSERT_PTR_EQ(k1->ed25519_sk, NULL);
+	TEST_DONE();
+
+	TEST_START("equal KEY_ED25519/demoted KEY_ED25519");
+	ASSERT_INT_EQ(sshkey_equal(kf, k1), 1);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	TEST_START("equal mismatched key types");
+	ASSERT_INT_EQ(sshkey_equal(kd, kr), 0);
+	ASSERT_INT_EQ(sshkey_equal(kd, ke), 0);
+	ASSERT_INT_EQ(sshkey_equal(kr, ke), 0);
+	ASSERT_INT_EQ(sshkey_equal(ke, kf), 0);
+	ASSERT_INT_EQ(sshkey_equal(kd, kf), 0);
+	TEST_DONE();
+
+	TEST_START("equal different keys");
+	ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 768, &k1), 0);
+	ASSERT_INT_EQ(sshkey_equal(kr, k1), 0);
+	sshkey_free(k1);
+	ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &k1), 0);
+	ASSERT_INT_EQ(sshkey_equal(kd, k1), 0);
+	sshkey_free(k1);
+	ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &k1), 0);
+	ASSERT_INT_EQ(sshkey_equal(ke, k1), 0);
+	sshkey_free(k1);
+	ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 256, &k1), 0);
+	ASSERT_INT_EQ(sshkey_equal(kf, k1), 0);
+	sshkey_free(k1);
+	TEST_DONE();
+
+	sshkey_free(kr);
+	sshkey_free(kd);
+	sshkey_free(ke);
+	sshkey_free(kf);
+
+/* XXX certify test */
+/* XXX sign test */
+/* XXX verify test */
+
+	TEST_START("nested certificate");
+	ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0);
+	ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2,
+	    NULL), 0);
+	b = load_file("rsa_2");
+	ASSERT_INT_EQ(sshkey_parse_private_fileblob(b, "", "rsa_1",
+	    &k3, NULL), 0);
+	sshbuf_reset(b);
+	build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1);
+	ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4),
+	    SSH_ERR_KEY_CERT_INVALID_SIGN_KEY);
+	ASSERT_PTR_EQ(k4, NULL);
+	sshbuf_free(b);
+	sshkey_free(k1);
+	sshkey_free(k2);
+	sshkey_free(k3);
+	TEST_DONE();
+
+}
diff --git a/regress/unittests/sshkey/testdata/dsa_1 b/regress/unittests/sshkey/testdata/dsa_1
new file mode 100644
index 0000000..7517963
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCB2IZRhajAULw+W8SLX5kxD/88CuVIKqojrZD5C+4T5D4YwQ0L
+6DvbvPHRhid1jmL4VLrG1MfOQvFMbePC9ydvf6CKDK/LPb8Wiq0cR2uBit2CVDIo
+4M7bk4X9+u7AwgENNbEAbdNBJRuMxwJiv4OawFGmFaASFNqVCRaq7MzA8wIVAMHA
+azJLtfjdILh3uV77BT3MxGIPAoGASU6xzUFx2PG3g81RBIO09NauCcf/0EYpyMls
+xNJ3MrQnVPWQwqjFepsEcU95ItbsUVkav0mqW319Am6/EAvroYcCHDyo+JUAUPiL
+WXmF6eEMNa97aNM5cQQwzYQvqt+F2mjK4SPxQObCA3O/YEmB8xUtn09BPDP2r/4Z
+y2ywGIECgYB6/rbpAUv4klwv7fX+v5nBFB3pnt5QPZrC6BxDmhG1v5vdNkvIWo4t
+OYnxV/5O3vJQQGi81uA0LjrpH3K9HRos8QP7QnsDYdAYyqLekrFzmnQOxMnYoj0n
+rZBr07TFifBI/m+/vboaegF93/xyNiGcG39i9sWoUQ+Qu1rsdLLg7QIVAITGqmpX
+T8lOnqkCA3X/7XZfZKUb
+-----END DSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/dsa_1-cert.fp b/regress/unittests/sshkey/testdata/dsa_1-cert.fp
new file mode 100644
index 0000000..79009e5
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1-cert.fp
@@ -0,0 +1 @@
+6d:a9:24:3f:d5:b0:51:76:6d:98:2a:eb:64:ad:e1:3e
diff --git a/regress/unittests/sshkey/testdata/dsa_1-cert.pub b/regress/unittests/sshkey/testdata/dsa_1-cert.pub
new file mode 100644
index 0000000..ccc9e34
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1-cert.pub
@@ -0,0 +1 @@
+ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgyiDlcNJnT+1aDuTAT6IFROmPV36yZXS1+eg8j93Lbv4AAACBAIHYhlGFqMBQvD5bxItfmTEP/zwK5UgqqiOtkPkL7hPkPhjBDQvoO9u88dGGJ3WOYvhUusbUx85C8Uxt48L3J29/oIoMr8s9vxaKrRxHa4GK3YJUMijgztuThf367sDCAQ01sQBt00ElG4zHAmK/g5rAUaYVoBIU2pUJFqrszMDzAAAAFQDBwGsyS7X43SC4d7le+wU9zMRiDwAAAIBJTrHNQXHY8beDzVEEg7T01q4Jx//QRinIyWzE0ncytCdU9ZDCqMV6mwRxT3ki1uxRWRq/SapbfX0Cbr8QC+uhhwIcPKj4lQBQ+ItZeYXp4Qw1r3to0zlxBDDNhC+q34XaaMrhI/FA5sIDc79gSYHzFS2fT0E8M/av/hnLbLAYgQAAAIB6/rbpAUv4klwv7fX+v5nBFB3pnt5QPZrC6BxDmhG1v5vdNkvIWo4tOYnxV/5O3vJQQGi81uA0LjrpH3K9HRos8QP7QnsDYdAYyqLekrFzmnQOxMnYoj0nrZBr07TFifBI/m+/vboaegF93/xyNiGcG39i9sWoUQ+Qu1rsdLLg7QAAAAAAAAAGAAAAAgAAAAZqdWxpdXMAAAASAAAABWhvc3QxAAAABWhvc3QyAAAAADaLg2AAAAAATR3h4AAAAAAAAAAAAAAAAAAAAGgAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAAhuaXN0cDI1NgAAAEEEeFVBN9rCVt76ZAhb71aQxLwcmq5SigrJG8nRvoBI3Tzfa8/Sp16hupzUeHJht3/BNI8sPvcI1DMVTuOREstl6wAAAGQAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAEkAAAAgMIrMGDb0MQT95GiXw93m4l7D+ruiJKLclEP/e68J/GMAAAAhAMbXfc7vVtOU4ofibChKSTHAUrDotY+qr50UDVhCIBhJ  DSA test key #1
diff --git a/regress/unittests/sshkey/testdata/dsa_1.fp b/regress/unittests/sshkey/testdata/dsa_1.fp
new file mode 100644
index 0000000..79009e5
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.fp
@@ -0,0 +1 @@
+6d:a9:24:3f:d5:b0:51:76:6d:98:2a:eb:64:ad:e1:3e
diff --git a/regress/unittests/sshkey/testdata/dsa_1.fp.bb b/regress/unittests/sshkey/testdata/dsa_1.fp.bb
new file mode 100644
index 0000000..9d0d51a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.fp.bb
@@ -0,0 +1 @@
+xumel-lusic-nevym-gyfup-ginyg-deliv-tetam-humef-vykul-tadit-pixix
diff --git a/regress/unittests/sshkey/testdata/dsa_1.param.g b/regress/unittests/sshkey/testdata/dsa_1.param.g
new file mode 100644
index 0000000..deb2900
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.param.g
@@ -0,0 +1 @@
+494eb1cd4171d8f1b783cd510483b4f4d6ae09c7ffd04629c8c96cc4d27732b42754f590c2a8c57a9b04714f7922d6ec51591abf49aa5b7d7d026ebf100beba187021c3ca8f8950050f88b597985e9e10c35af7b68d339710430cd842faadf85da68cae123f140e6c20373bf604981f3152d9f4f413c33f6affe19cb6cb01881
diff --git a/regress/unittests/sshkey/testdata/dsa_1.param.priv b/regress/unittests/sshkey/testdata/dsa_1.param.priv
new file mode 100644
index 0000000..314148b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.param.priv
@@ -0,0 +1 @@
+0084c6aa6a574fc94e9ea9020375ffed765f64a51b
diff --git a/regress/unittests/sshkey/testdata/dsa_1.param.pub b/regress/unittests/sshkey/testdata/dsa_1.param.pub
new file mode 100644
index 0000000..bde5b10
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.param.pub
@@ -0,0 +1 @@
+7afeb6e9014bf8925c2fedf5febf99c1141de99ede503d9ac2e81c439a11b5bf9bdd364bc85a8e2d3989f157fe4edef2504068bcd6e0342e3ae91f72bd1d1a2cf103fb427b0361d018caa2de92b1739a740ec4c9d8a23d27ad906bd3b4c589f048fe6fbfbdba1a7a017ddffc7236219c1b7f62f6c5a8510f90bb5aec74b2e0ed
diff --git a/regress/unittests/sshkey/testdata/dsa_1.pub b/regress/unittests/sshkey/testdata/dsa_1.pub
new file mode 100644
index 0000000..51c2c1b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAIHYhlGFqMBQvD5bxItfmTEP/zwK5UgqqiOtkPkL7hPkPhjBDQvoO9u88dGGJ3WOYvhUusbUx85C8Uxt48L3J29/oIoMr8s9vxaKrRxHa4GK3YJUMijgztuThf367sDCAQ01sQBt00ElG4zHAmK/g5rAUaYVoBIU2pUJFqrszMDzAAAAFQDBwGsyS7X43SC4d7le+wU9zMRiDwAAAIBJTrHNQXHY8beDzVEEg7T01q4Jx//QRinIyWzE0ncytCdU9ZDCqMV6mwRxT3ki1uxRWRq/SapbfX0Cbr8QC+uhhwIcPKj4lQBQ+ItZeYXp4Qw1r3to0zlxBDDNhC+q34XaaMrhI/FA5sIDc79gSYHzFS2fT0E8M/av/hnLbLAYgQAAAIB6/rbpAUv4klwv7fX+v5nBFB3pnt5QPZrC6BxDmhG1v5vdNkvIWo4tOYnxV/5O3vJQQGi81uA0LjrpH3K9HRos8QP7QnsDYdAYyqLekrFzmnQOxMnYoj0nrZBr07TFifBI/m+/vboaegF93/xyNiGcG39i9sWoUQ+Qu1rsdLLg7Q== DSA test key #1
diff --git a/regress/unittests/sshkey/testdata/dsa_1_pw b/regress/unittests/sshkey/testdata/dsa_1_pw
new file mode 100644
index 0000000..1bedcb0
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1_pw
@@ -0,0 +1,15 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,65B3055CF40728FF588846F0AEFE21B2
+
+I3cUBSbhjltkTMvTaDABixfwLr8faxL9/YOoEFenmBj0JwwrSV7L8VGbb68BbwCr
+5EOgySFEazgXUbiuILg47lWxp/IKegz1KrO6bXoE1bKT+UxjrI+e8CDi4kpEh98F
+jM6V0QZmotMVwJh6NIfuuOBN92mS8In8remGGBA08VWPjW1CsmjmTDFNzOW5Uzo9
+gG9dM08NljQ8Mf3L2iKoTpLQVr//0Q//0Ei3qCEUOvOOH05mWiecGwPAiCSH2jSO
+GlP59jbwxfIZ2klGrj9D8xCBzTZgdHDlS2cdnJ0GasaPiFnWwX91zaatK+vCvWp6
+apWY6biRn0g9EGJob9YZ6eg3ZGHcFsf/7yDbSjuG3Uj8FhmrP/MkK7Ht7db2hiGL
+9uUrNcZhLUFyynTcEfBOFuAtoqktDNTN2VjMj9szJWipF8U9hGeRfw4hFeMXYPHD
+k/+j4qS4fc5EAx1Vd6iMXRzxiUre8GGzyq2nSm1POtyQPG+3UQTRU3zBBudIx9N9
+WCXWHw0+xNHgOX/HtLUkq+2ghxnU+6Whew5eqSdKLMoB7KIKxsxf8wNkv4yOM1KJ
+JWXaXOCyIWclCuc1Uj27Zw==
+-----END DSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/dsa_2 b/regress/unittests/sshkey/testdata/dsa_2
new file mode 100644
index 0000000..2ad7393
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_2
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDzY25r/QuRHe5YvbwajDpB4/DyY3LH/OTVWcQdflDH2xH6823W
+H2i7FwnuYzsAJkbM1L9n3N9bOXhiGmYIpUKfkE1EKRekNnLW9D0/AvkVzcBN/Lqc
+zy4TxmE7oxClIS+6uksoRHhohFkHPWZDYTxo6mD5vVfzCh2jSSzjEhzFLwIVANtk
+v40w5aRP8C8TQciVJCUy5yp1AoGBAO+s5wkzEftttboUCci3pK0L9wUPHkhTNgC+
+sFjdtiVVpptGkLsujyllEyIFChVUrN5ZNgjv7bzSEe0FSU0XtmZ77GU96ff7jWmD
+9xUqm4aIwu/3DSgitOO+XLgb2J08eLY+Lglp40AoWFfwy57flpPMT4q5nk77QfS1
+gzC2X0CtAoGAPfbEG6KUOec9H1xfnwb8AVCk6jOy+XfiGtE3cnlECNQjQkPcp1Jm
+CrhrEh1rRmOwJdMkDLhmOHy6IFnzvj85IAm9qY6M2f8svZ/ASCAnQ6SnHDwhl3eO
+ZQPi03Fka3QXjkwJb/gnmoWuGayM7dPbJg0Ib62GrPGj6/vkaQsGy3ACFQDL5o4e
+vjA1Kf3kA2WYhOy/8kfeJg==
+-----END DSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/dsa_2.fp b/regress/unittests/sshkey/testdata/dsa_2.fp
new file mode 100644
index 0000000..a9a2a45
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_2.fp
@@ -0,0 +1 @@
+3d:fb:a3:22:95:17:89:1f:24:31:e7:ec:9f:ce:09:0b
diff --git a/regress/unittests/sshkey/testdata/dsa_2.fp.bb b/regress/unittests/sshkey/testdata/dsa_2.fp.bb
new file mode 100644
index 0000000..788bffe
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_2.fp.bb
@@ -0,0 +1 @@
+xuzoh-nuhut-lyrum-luhap-givyl-nygiz-nybyr-higes-pahor-nivic-zyxex
diff --git a/regress/unittests/sshkey/testdata/dsa_2.pub b/regress/unittests/sshkey/testdata/dsa_2.pub
new file mode 100644
index 0000000..da4ac7f
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_2.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAPNjbmv9C5Ed7li9vBqMOkHj8PJjcsf85NVZxB1+UMfbEfrzbdYfaLsXCe5jOwAmRszUv2fc31s5eGIaZgilQp+QTUQpF6Q2ctb0PT8C+RXNwE38upzPLhPGYTujEKUhL7q6SyhEeGiEWQc9ZkNhPGjqYPm9V/MKHaNJLOMSHMUvAAAAFQDbZL+NMOWkT/AvE0HIlSQlMucqdQAAAIEA76znCTMR+221uhQJyLekrQv3BQ8eSFM2AL6wWN22JVWmm0aQuy6PKWUTIgUKFVSs3lk2CO/tvNIR7QVJTRe2ZnvsZT3p9/uNaYP3FSqbhojC7/cNKCK0475cuBvYnTx4tj4uCWnjQChYV/DLnt+Wk8xPirmeTvtB9LWDMLZfQK0AAACAPfbEG6KUOec9H1xfnwb8AVCk6jOy+XfiGtE3cnlECNQjQkPcp1JmCrhrEh1rRmOwJdMkDLhmOHy6IFnzvj85IAm9qY6M2f8svZ/ASCAnQ6SnHDwhl3eOZQPi03Fka3QXjkwJb/gnmoWuGayM7dPbJg0Ib62GrPGj6/vkaQsGy3A= DSA test key #2
diff --git a/regress/unittests/sshkey/testdata/dsa_n b/regress/unittests/sshkey/testdata/dsa_n
new file mode 100644
index 0000000..7517963
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_n
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCB2IZRhajAULw+W8SLX5kxD/88CuVIKqojrZD5C+4T5D4YwQ0L
+6DvbvPHRhid1jmL4VLrG1MfOQvFMbePC9ydvf6CKDK/LPb8Wiq0cR2uBit2CVDIo
+4M7bk4X9+u7AwgENNbEAbdNBJRuMxwJiv4OawFGmFaASFNqVCRaq7MzA8wIVAMHA
+azJLtfjdILh3uV77BT3MxGIPAoGASU6xzUFx2PG3g81RBIO09NauCcf/0EYpyMls
+xNJ3MrQnVPWQwqjFepsEcU95ItbsUVkav0mqW319Am6/EAvroYcCHDyo+JUAUPiL
+WXmF6eEMNa97aNM5cQQwzYQvqt+F2mjK4SPxQObCA3O/YEmB8xUtn09BPDP2r/4Z
+y2ywGIECgYB6/rbpAUv4klwv7fX+v5nBFB3pnt5QPZrC6BxDmhG1v5vdNkvIWo4t
+OYnxV/5O3vJQQGi81uA0LjrpH3K9HRos8QP7QnsDYdAYyqLekrFzmnQOxMnYoj0n
+rZBr07TFifBI/m+/vboaegF93/xyNiGcG39i9sWoUQ+Qu1rsdLLg7QIVAITGqmpX
+T8lOnqkCA3X/7XZfZKUb
+-----END DSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/dsa_n_pw b/regress/unittests/sshkey/testdata/dsa_n_pw
new file mode 100644
index 0000000..568f851
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_n_pw
@@ -0,0 +1,21 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABB7JzB0sx
+h4pg63zhB6eD3vAAAAEAAAAAEAAAGxAAAAB3NzaC1kc3MAAACBAIHYhlGFqMBQvD5bxItf
+mTEP/zwK5UgqqiOtkPkL7hPkPhjBDQvoO9u88dGGJ3WOYvhUusbUx85C8Uxt48L3J29/oI
+oMr8s9vxaKrRxHa4GK3YJUMijgztuThf367sDCAQ01sQBt00ElG4zHAmK/g5rAUaYVoBIU
+2pUJFqrszMDzAAAAFQDBwGsyS7X43SC4d7le+wU9zMRiDwAAAIBJTrHNQXHY8beDzVEEg7
+T01q4Jx//QRinIyWzE0ncytCdU9ZDCqMV6mwRxT3ki1uxRWRq/SapbfX0Cbr8QC+uhhwIc
+PKj4lQBQ+ItZeYXp4Qw1r3to0zlxBDDNhC+q34XaaMrhI/FA5sIDc79gSYHzFS2fT0E8M/
+av/hnLbLAYgQAAAIB6/rbpAUv4klwv7fX+v5nBFB3pnt5QPZrC6BxDmhG1v5vdNkvIWo4t
+OYnxV/5O3vJQQGi81uA0LjrpH3K9HRos8QP7QnsDYdAYyqLekrFzmnQOxMnYoj0nrZBr07
+TFifBI/m+/vboaegF93/xyNiGcG39i9sWoUQ+Qu1rsdLLg7QAAAeDozqkOSFq7z2LnfJ2b
+jVVwsNdNDn1K3DBONYaoz3R1CyNSmfdTOylCkw/VXQ/7Wlw52+ot/mEIdtjv6uK7NCjAyL
+XLGkq2yMRmitPFxiLRSNo9/Sirpviaq7zJyOBbZiB+wrJgnSdg+185u1t5Qd19hi+XEKcM
+DyTfAj6MPGe/uBmuxIVaVEf9BknyQ74+D5HD6KApcxWI6WNJH9hAkSON8hA1EUWRc+N2hD
+624dEkuJBkCBCgmFbfD7QthBXrGMuSo78Xz0XRpuP+cOQvs/U2wl8OLXuqyzmZtGnDGfjW
+9Z2qF4sKUKV2A3Q97WAjm/p04TxDXUEChI3D12dbwN0dGYEZW2XSBYxhK/YbTpjKKXzpJs
+R7U2Avm1krEql7+4fEb876i1+/6w2aFBfn8tx5vvdRehvIXqcg6n4KhIO7d3MS62A19m68
+OYQu1veaUxu9oO2D5byV0GIqZbVWCtaVh/8hLQcGMgz+43HGIMHiJRX9EWenOqEeK7Pam0
+BLkCoFycbGa3fI/reyoQ/g/tlmHjq3kdO9SKZYIcUPk4tnImStHsPEU1X7/WbvV+j0jTtZ
+nxJ2E/z5gdeDeJ9VJcdwofd6BpEwd2WML1o3kZYNwY+K2HJ3JnYfWsJanb6YlRA=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1 b/regress/unittests/sshkey/testdata/ecdsa_1
new file mode 100644
index 0000000..9b8b9f4
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIDUJpHhcwtTxAYqTeBC2WNcZJ3VJrAI97F2n2PeootjCoAoGCCqGSM49
+AwEHoUQDQgAEeFVBN9rCVt76ZAhb71aQxLwcmq5SigrJG8nRvoBI3Tzfa8/Sp16h
+upzUeHJht3/BNI8sPvcI1DMVTuOREstl6w==
+-----END EC PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp b/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp
new file mode 100644
index 0000000..fec523c
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp
@@ -0,0 +1 @@
+db:df:20:25:bf:74:fc:1d:61:2f:c0:cd:53:7f:a0:69
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1-cert.pub b/regress/unittests/sshkey/testdata/ecdsa_1-cert.pub
new file mode 100644
index 0000000..1dde064
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1-cert.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg99cLkLZdAh1Q9TLiiFjDgLeXcncoQ2ChPj6vheH5aDAAAAAIbmlzdHAyNTYAAABBBHhVQTfawlbe+mQIW+9WkMS8HJquUooKyRvJ0b6ASN0832vP0qdeobqc1HhyYbd/wTSPLD73CNQzFU7jkRLLZesAAAAAAAAABwAAAAIAAAAGanVsaXVzAAAAEgAAAAVob3N0MQAAAAVob3N0MgAAAAA2i4NgAAAAAE0d4eAAAAAAAAAAAAAAAAAAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHhVQTfawlbe+mQIW+9WkMS8HJquUooKyRvJ0b6ASN0832vP0qdeobqc1HhyYbd/wTSPLD73CNQzFU7jkRLLZesAAABlAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABKAAAAIQCNyzewlmw65HO5pgVlhNhTds90xhHWG7E26+w37vS6AQAAACEAofQD+jXVJIw0JFuL/4pEpHV8LA9swBOlr+0QSHOvrO8=  ECDSA test key #1
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.fp b/regress/unittests/sshkey/testdata/ecdsa_1.fp
new file mode 100644
index 0000000..fec523c
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.fp
@@ -0,0 +1 @@
+db:df:20:25:bf:74:fc:1d:61:2f:c0:cd:53:7f:a0:69
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.fp.bb b/regress/unittests/sshkey/testdata/ecdsa_1.fp.bb
new file mode 100644
index 0000000..9816fec
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.fp.bb
@@ -0,0 +1 @@
+xeroh-pefer-fypid-kipem-fosag-ludoz-vilym-nuvoz-rilyv-nonut-raxex
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.param.curve b/regress/unittests/sshkey/testdata/ecdsa_1.param.curve
new file mode 100644
index 0000000..fa04004
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.param.curve
@@ -0,0 +1 @@
+prime256v1
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.param.priv b/regress/unittests/sshkey/testdata/ecdsa_1.param.priv
new file mode 100644
index 0000000..7196f0c
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.param.priv
@@ -0,0 +1 @@
+3509a4785cc2d4f1018a937810b658d719277549ac023dec5da7d8f7a8a2d8c2
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.param.pub b/regress/unittests/sshkey/testdata/ecdsa_1.param.pub
new file mode 100644
index 0000000..189f318
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.param.pub
@@ -0,0 +1 @@
+0478554137dac256defa64085bef5690c4bc1c9aae528a0ac91bc9d1be8048dd3cdf6bcfd2a75ea1ba9cd4787261b77fc1348f2c3ef708d433154ee39112cb65eb
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.pub b/regress/unittests/sshkey/testdata/ecdsa_1.pub
new file mode 100644
index 0000000..cea2861
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHhVQTfawlbe+mQIW+9WkMS8HJquUooKyRvJ0b6ASN0832vP0qdeobqc1HhyYbd/wTSPLD73CNQzFU7jkRLLZes= ECDSA test key #1
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1_pw b/regress/unittests/sshkey/testdata/ecdsa_1_pw
new file mode 100644
index 0000000..7fcf57a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1_pw
@@ -0,0 +1,8 @@
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,332EEE2B8008A91D1F4342B9DEBE4FEA
+
+nMCab7D2wbVoKZvM37ZbTXiajSmyvWFQd3Mt3zeeEBoL6ib/48BFDogWlcDvRP7y
+tgKYhqK7JBO4GjSssL4Bu/rQgNK/0ZmS/V7hLN7wsU3DcrHYhfHknL8LbRfiJarB
+772nLAie9oaQcZZloNVa477CBGh7WXux/vRk2NlJ0Uo=
+-----END EC PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2 b/regress/unittests/sshkey/testdata/ecdsa_2
new file mode 100644
index 0000000..651b00c
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIB7SsuJvR+4aK3Js4gEaJ5UDEa2hJTCBM+/PBYv9ZUkf9PohUvfPfh
+xHRcF6tUhZDmChFeNQpt3sic2uTXa4lU8oigBwYFK4EEACOhgYkDgYYABABLAXz5
+fCAiumZWlWqzG5NxJx1a17WgZ2o+ffYrAJgXVrGGJudmIZSCDWFABtpuY7Ws3zRa
+CM3DZj+ua+qMWsUysQGwiC6n1YEUdVZste5Vdh1YqhImJcT3//TzJ6lfMaUpJxdU
+MeYe8bw+zuNAEJ+ax8W6lWKQwu4sh3Ffc6WmU+qYkg==
+-----END EC PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.fp b/regress/unittests/sshkey/testdata/ecdsa_2.fp
new file mode 100644
index 0000000..a8b8320
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.fp
@@ -0,0 +1 @@
+1e:54:1d:9d:43:f0:c9:2b:68:7a:6a:c3:33:36:66:92
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.fp.bb b/regress/unittests/sshkey/testdata/ecdsa_2.fp.bb
new file mode 100644
index 0000000..5863db4
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.fp.bb
@@ -0,0 +1 @@
+xefak-fyfim-lytem-nusir-kycog-vybyt-peguk-deniv-pukub-bydyr-rexux
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.param.curve b/regress/unittests/sshkey/testdata/ecdsa_2.param.curve
new file mode 100644
index 0000000..617ea2f
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.param.curve
@@ -0,0 +1 @@
+secp521r1
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.param.priv b/regress/unittests/sshkey/testdata/ecdsa_2.param.priv
new file mode 100644
index 0000000..66d8823
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.param.priv
@@ -0,0 +1 @@
+01ed2b2e26f47ee1a2b726ce2011a27950311ada125308133efcf058bfd65491ff4fa2152f7cf7e1c4745c17ab548590e60a115e350a6ddec89cdae4d76b8954f288
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.param.pub b/regress/unittests/sshkey/testdata/ecdsa_2.param.pub
new file mode 100644
index 0000000..646a376
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.param.pub
@@ -0,0 +1 @@
+04004b017cf97c2022ba6656956ab31b9371271d5ad7b5a0676a3e7df62b00981756b18626e7662194820d614006da6e63b5acdf345a08cdc3663fae6bea8c5ac532b101b0882ea7d5811475566cb5ee55761d58aa122625c4f7fff4f327a95f31a52927175431e61ef1bc3ecee340109f9ac7c5ba956290c2ee2c87715f73a5a653ea9892
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.pub b/regress/unittests/sshkey/testdata/ecdsa_2.pub
new file mode 100644
index 0000000..2ca38b7
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBABLAXz5fCAiumZWlWqzG5NxJx1a17WgZ2o+ffYrAJgXVrGGJudmIZSCDWFABtpuY7Ws3zRaCM3DZj+ua+qMWsUysQGwiC6n1YEUdVZste5Vdh1YqhImJcT3//TzJ6lfMaUpJxdUMeYe8bw+zuNAEJ+ax8W6lWKQwu4sh3Ffc6WmU+qYkg== ECDSA test key #2
diff --git a/regress/unittests/sshkey/testdata/ecdsa_n b/regress/unittests/sshkey/testdata/ecdsa_n
new file mode 100644
index 0000000..9b8b9f4
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_n
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIDUJpHhcwtTxAYqTeBC2WNcZJ3VJrAI97F2n2PeootjCoAoGCCqGSM49
+AwEHoUQDQgAEeFVBN9rCVt76ZAhb71aQxLwcmq5SigrJG8nRvoBI3Tzfa8/Sp16h
+upzUeHJht3/BNI8sPvcI1DMVTuOREstl6w==
+-----END EC PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_n_pw b/regress/unittests/sshkey/testdata/ecdsa_n_pw
new file mode 100644
index 0000000..1a232a5
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_n_pw
@@ -0,0 +1,9 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABBjrPF4oU
+razQUC36K0kiJSAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz
+dHAyNTYAAABBBHhVQTfawlbe+mQIW+9WkMS8HJquUooKyRvJ0b6ASN0832vP0qdeobqc1H
+hyYbd/wTSPLD73CNQzFU7jkRLLZesAAACwRIjJkfLwAv6pn+FV4zyB7jwNpiM/Tvi8G9L1
+tyjowAbH5QspKcUk2QlGwAfDzZkwZaeO3AHN+jrxUZe59U39nBPUQTJtfwHB/9YDQmkxDf
+PSjPhSUgTJTjO7ZnJhiBhopSecrLlw9jEG3aU6jXrtLHvoeWsqgNC4FPR+NONY56Cp6HH/
+xcNMcG3bdfsLV7/aKN6L8xFOcwv5PZguUX+akbm28L2RtdwomHLlinxCBZQ=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_1 b/regress/unittests/sshkey/testdata/ed25519_1
new file mode 100644
index 0000000..9834e6b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACD9nC84xPJD/K1WHPNss8ONwRTYYXhE+JfNMTACxwMC9QAAAJgHI6RaByOk
+WgAAAAtzc2gtZWQyNTUxOQAAACD9nC84xPJD/K1WHPNss8ONwRTYYXhE+JfNMTACxwMC9Q
+AAAEBTSW4tcSIyBvJIs9X0+veV3KEnF5tMFTuDRn2UUCDg4f2cLzjE8kP8rVYc82yzw43B
+FNhheET4l80xMALHAwL1AAAAE0VEMjU1MTkgdGVzdCBrZXkgIzEBAg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_1-cert.fp b/regress/unittests/sshkey/testdata/ed25519_1-cert.fp
new file mode 100644
index 0000000..a1065af
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1-cert.fp
@@ -0,0 +1 @@
+c5:bc:c6:f0:71:ff:18:01:b6:bb:20:0e:5c:c9:45:dd
diff --git a/regress/unittests/sshkey/testdata/ed25519_1-cert.pub b/regress/unittests/sshkey/testdata/ed25519_1-cert.pub
new file mode 100644
index 0000000..e1af85b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1-cert.pub
@@ -0,0 +1 @@
+ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAICJMFRc+O68lpgxZhFEBSABACLSyhq6uRr5p64SX7rG8AAAAIP2cLzjE8kP8rVYc82yzw43BFNhheET4l80xMALHAwL1AAAAAAAAAAgAAAACAAAABmp1bGl1cwAAABIAAAAFaG9zdDEAAAAFaG9zdDIAAAAANouDYAAAAABNHeHgAAAAAAAAAAAAAAAAAAAAaAAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQR4VUE32sJW3vpkCFvvVpDEvByarlKKCskbydG+gEjdPN9rz9KnXqG6nNR4cmG3f8E0jyw+9wjUMxVO45ESy2XrAAAAZQAAABNlY2RzYS1zaGEyLW5pc3RwMjU2AAAASgAAACEAmB/afp9JrHKRDZjHg7t4gguDZUlM7TbJh/QGWBJtKNwAAAAhAIfciGrKUngYx8c+MrLs9xm/H15UjQ1b/hmDjHPnBUXJ  ED25519 test key #1
diff --git a/regress/unittests/sshkey/testdata/ed25519_1.fp b/regress/unittests/sshkey/testdata/ed25519_1.fp
new file mode 100644
index 0000000..a1065af
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1.fp
@@ -0,0 +1 @@
+c5:bc:c6:f0:71:ff:18:01:b6:bb:20:0e:5c:c9:45:dd
diff --git a/regress/unittests/sshkey/testdata/ed25519_1.fp.bb b/regress/unittests/sshkey/testdata/ed25519_1.fp.bb
new file mode 100644
index 0000000..19fed08
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1.fp.bb
@@ -0,0 +1 @@
+xunad-cibit-losah-sapes-fegor-fypyg-sifuv-buciv-cacim-votid-guxex
diff --git a/regress/unittests/sshkey/testdata/ed25519_1.pub b/regress/unittests/sshkey/testdata/ed25519_1.pub
new file mode 100644
index 0000000..585c723
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP2cLzjE8kP8rVYc82yzw43BFNhheET4l80xMALHAwL1 ED25519 test key #1
diff --git a/regress/unittests/sshkey/testdata/ed25519_1_pw b/regress/unittests/sshkey/testdata/ed25519_1_pw
new file mode 100644
index 0000000..995e4c0
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1_pw
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABDAj0Bpln
+j9yho1+E35Cs50AAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIP2cLzjE8kP8rVYc
+82yzw43BFNhheET4l80xMALHAwL1AAAAkOUMXMXJCs4Ra9eTz7ZmI+62mynIdc75adQIJ6
+Y1FhHU1FiNKA6thIsJQ2GkVraYUbsRr2cSId0wOdDyqCz8qGtUJGJf/CpC8xGyDiFxSRmX
+Q/jVwSPluusjq3hXSXgVkhMCl7x6wvdOYrgir1JAmt7xZ+GH16h9UshdQJQP2WRreYzBGa
+epCGVXiKDRt1h6qQ==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_2 b/regress/unittests/sshkey/testdata/ed25519_2
new file mode 100644
index 0000000..cffc23e
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_2
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACD9RTuggxlEg440MCY7b8x7AXErFCkvyqOBzGa2H72HgAAAAJjVTVis1U1Y
+rAAAAAtzc2gtZWQyNTUxOQAAACD9RTuggxlEg440MCY7b8x7AXErFCkvyqOBzGa2H72HgA
+AAAECg5ZFCAGyGayR8cfdh9Z+atBw2D7iDCyhlM/Z9BhS8Y/1FO6CDGUSDjjQwJjtvzHsB
+cSsUKS/Ko4HMZrYfvYeAAAAAE0VEMjU1MTkgdGVzdCBrZXkgIzEBAg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_2.fp b/regress/unittests/sshkey/testdata/ed25519_2.fp
new file mode 100644
index 0000000..bd9bdf1
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_2.fp
@@ -0,0 +1 @@
+8a:9b:6b:7a:72:4a:33:e7:82:f4:44:36:4f:03:ab:fb
diff --git a/regress/unittests/sshkey/testdata/ed25519_2.fp.bb b/regress/unittests/sshkey/testdata/ed25519_2.fp.bb
new file mode 100644
index 0000000..d344f8b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_2.fp.bb
@@ -0,0 +1 @@
+xopaz-sytem-gohun-gekug-nupyz-mizeb-satur-gykyz-bytuk-cynak-zoxax
diff --git a/regress/unittests/sshkey/testdata/ed25519_2.pub b/regress/unittests/sshkey/testdata/ed25519_2.pub
new file mode 100644
index 0000000..36f769a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_2.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP1FO6CDGUSDjjQwJjtvzHsBcSsUKS/Ko4HMZrYfvYeA ED25519 test key #1
diff --git a/regress/unittests/sshkey/testdata/pw b/regress/unittests/sshkey/testdata/pw
new file mode 100644
index 0000000..8a1dff9
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/pw
@@ -0,0 +1 @@
+mekmitasdigoat
diff --git a/regress/unittests/sshkey/testdata/rsa1_1 b/regress/unittests/sshkey/testdata/rsa1_1
new file mode 100644
index 0000000..2ec1d9e
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1
Binary files differ
diff --git a/regress/unittests/sshkey/testdata/rsa1_1.fp b/regress/unittests/sshkey/testdata/rsa1_1.fp
new file mode 100644
index 0000000..f124ea6
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1.fp
@@ -0,0 +1 @@
+ca:c8:b5:7e:5e:c3:0d:b9:7a:01:08:07:e6:8d:84:ff
diff --git a/regress/unittests/sshkey/testdata/rsa1_1.fp.bb b/regress/unittests/sshkey/testdata/rsa1_1.fp.bb
new file mode 100644
index 0000000..cbcd469
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1.fp.bb
@@ -0,0 +1 @@
+xolod-lezac-hozas-zyvam-femup-resyn-tabeh-cimil-todab-pimak-maxox
diff --git a/regress/unittests/sshkey/testdata/rsa1_1.param.n b/regress/unittests/sshkey/testdata/rsa1_1.param.n
new file mode 100644
index 0000000..50b9f68
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1.param.n
@@ -0,0 +1 @@
+00c410f14bcebcbddc6ffeaa710252ad90fbef0d050ec87d3383a9d238d6711fbef589e4878403c264c7966fe49bad711536dce5d87a955b85e59407cb05b42fa7403d9f69ff0939dc6c706bdcf06b6b261d989bd36b3285406a2ed222823c2395
diff --git a/regress/unittests/sshkey/testdata/rsa1_1.pub b/regress/unittests/sshkey/testdata/rsa1_1.pub
new file mode 100644
index 0000000..bc70397
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1.pub
@@ -0,0 +1 @@
+768 65537 1189048026044302003027146850139461857907776498392388644081572317839873971656566933581374195515931390619470169918301657448827055049126798186766951463208246494942453808397018298947013383501856813897052663039958494425741000753698055061 RSA1 test key #1
diff --git a/regress/unittests/sshkey/testdata/rsa1_1_pw b/regress/unittests/sshkey/testdata/rsa1_1_pw
new file mode 100644
index 0000000..a3a18aa
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1_pw
Binary files differ
diff --git a/regress/unittests/sshkey/testdata/rsa1_2 b/regress/unittests/sshkey/testdata/rsa1_2
new file mode 100644
index 0000000..ae26629
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2
Binary files differ
diff --git a/regress/unittests/sshkey/testdata/rsa1_2.fp b/regress/unittests/sshkey/testdata/rsa1_2.fp
new file mode 100644
index 0000000..8b3bdd3
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2.fp
@@ -0,0 +1 @@
+81:76:19:cb:e3:ea:6f:5d:44:0d:c2:0b:de:f1:57:c4
diff --git a/regress/unittests/sshkey/testdata/rsa1_2.fp.bb b/regress/unittests/sshkey/testdata/rsa1_2.fp.bb
new file mode 100644
index 0000000..d519e7b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2.fp.bb
@@ -0,0 +1 @@
+xocoh-kufyf-rirac-kepuc-gurig-mekog-pylir-fezyd-nosub-govug-lyxyx
diff --git a/regress/unittests/sshkey/testdata/rsa1_2.param.n b/regress/unittests/sshkey/testdata/rsa1_2.param.n
new file mode 100644
index 0000000..6a88ee8
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2.param.n
@@ -0,0 +1 @@
+00f41a2e0ea0e61ba8c26cf6e1bd44a78406681186a7791de3242bedc244e06c17a18747fb88b1380aeba3c857923452b9e38673817bd1a23f7d2075923b1d95d9969bbcd21aa04dfe467e4c7d8a47a10bd63dd6dce4ffe779a61f4540bcfcd9300d69055260be095e5e8460e82396779c0a50625fb85604899e443135ca261860351264b5cd9347b3b2d0493dc8ab58a76739834e94e6a931a81b47ec07a0d18e6326cf141c4cecf21ce33e55c4337b58e81f98ba37aa2363c4b7b9b681832fc82bfd065e78225963b5dee3339fc5f93b1e03fb23b944af1044c428face1e9074cac094e1b1466567bcd0052c7a3cd54413e0223cd3ead772c224fe9992a1cc4d
diff --git a/regress/unittests/sshkey/testdata/rsa1_2.pub b/regress/unittests/sshkey/testdata/rsa1_2.pub
new file mode 100644
index 0000000..c57a552
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2.pub
@@ -0,0 +1 @@
+2048 65537 30815056206845718337883693475648720850145825019377625660339254990170671928186378018861225635606515759973597729576094610770872780661576141002020091115398326221356676709078132441993985409561447755934597661311399662597377239284991122793182116387265444497738700221133645372503575578155284370786624391167692459891729408171168746091407569853493645212173229529277332482208795686490659301613799014974247858014846717332898701883748838319394666276585141978582467494951081034069208462692298663692548804886954137194606203245934935998707318505433583480495694779849614216589821145199486122690013311036780783985671309143185809329229 RSA1 test key #2
diff --git a/regress/unittests/sshkey/testdata/rsa_1 b/regress/unittests/sshkey/testdata/rsa_1
new file mode 100644
index 0000000..a84a9e2
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1
@@ -0,0 +1,12 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIByQIBAAJhAKAJGOfpr4S2inakOMcqjGQ1RLNwp4FWvWYc+xxnAqfJS7vwZ8ie
+2fcniZMS69o9CXiACUw2LYbNGZMfrnzjQEaKlObDi5HB1XNE+9z01m2GS9XH+Eg0
+ilNeAx/hfNEDVQIDAQABAmB8O3OtHHhXYskMHqHA4qPHap6hWZN+0RIIQfkhbEng
+bGAxTgeS8tWrinK+zFJwwS3tYmSc8YfT/4gX/DG1nudv+Pjjhwom/HMTiK/Tw4JN
+ZhWCPKB8T1rICkGAtbMq2KECMQDTa9o6g/Nb2zkvJq+04SQ5ivqZdWXaeZixz1Xt
+JKgqRLoMxny81E/LaeeKXfNACE0CMQDBx4hGEBlm8aJwj6SdZ50Ulu8c4hz4ZcJo
+v2T+BY8ogmlaF1ADcFXeHDmE7Cg16ykCMF7zTCIFirERRqBXdof8qSEyupNa9zBk
+deA9ZrDHSsMY9JmyNukzTNblLDinMwzp7QIwUq/O4X6rKDdBhmB08MmuyINjQuLl
+U8UwQLwy3wYGQVXsmInMFbuQmHdYv/R5cBCJAjAquE/FnCRxuI2NEhoqrO3FG0wO
+cByLc/Svz1ct3eGUMabUxfQdi8Ka97gv9CW9EbI=
+-----END RSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/rsa_1-cert.fp b/regress/unittests/sshkey/testdata/rsa_1-cert.fp
new file mode 100644
index 0000000..6600234
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1-cert.fp
@@ -0,0 +1 @@
+93:53:33:f1:ca:bc:c2:df:a1:a2:0e:df:2d:d4:32:77
diff --git a/regress/unittests/sshkey/testdata/rsa_1-cert.pub b/regress/unittests/sshkey/testdata/rsa_1-cert.pub
new file mode 100644
index 0000000..aea5a04
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1-cert.pub
@@ -0,0 +1 @@
+ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgAkIaUrWrYvXkf55DvHtHsjLNCn22Hvx4PpKyeW7fvA0AAAADAQABAAAAYQCgCRjn6a+Etop2pDjHKoxkNUSzcKeBVr1mHPscZwKnyUu78GfIntn3J4mTEuvaPQl4gAlMNi2GzRmTH65840BGipTmw4uRwdVzRPvc9NZthkvVx/hINIpTXgMf4XzRA1UAAAAAAAAABQAAAAIAAAAGanVsaXVzAAAAEgAAAAVob3N0MQAAAAVob3N0MgAAAAA2i4NgAAAAAE0d4eAAAAAAAAAAAAAAAAAAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHhVQTfawlbe+mQIW+9WkMS8HJquUooKyRvJ0b6ASN0832vP0qdeobqc1HhyYbd/wTSPLD73CNQzFU7jkRLLZesAAABlAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABKAAAAIQDEZOWcEwfnm+mpfKMsGdXgWkTZDM9FD7tXGjHhTAIXnwAAACEA4eTYbu8nl1ycJnHUAWmy4sayJNm4vHZNYH1Wzvsh3dQ=  RSA test key #1
diff --git a/regress/unittests/sshkey/testdata/rsa_1.fp b/regress/unittests/sshkey/testdata/rsa_1.fp
new file mode 100644
index 0000000..6600234
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.fp
@@ -0,0 +1 @@
+93:53:33:f1:ca:bc:c2:df:a1:a2:0e:df:2d:d4:32:77
diff --git a/regress/unittests/sshkey/testdata/rsa_1.fp.bb b/regress/unittests/sshkey/testdata/rsa_1.fp.bb
new file mode 100644
index 0000000..11f62b4
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.fp.bb
@@ -0,0 +1 @@
+xiriz-botoh-migez-rorom-fekat-hytar-bykys-selos-hanez-sukil-moxox
diff --git a/regress/unittests/sshkey/testdata/rsa_1.param.n b/regress/unittests/sshkey/testdata/rsa_1.param.n
new file mode 100644
index 0000000..6c83fd7
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.param.n
@@ -0,0 +1 @@
+00a00918e7e9af84b68a76a438c72a8c643544b370a78156bd661cfb1c6702a7c94bbbf067c89ed9f727899312ebda3d097880094c362d86cd19931fae7ce340468a94e6c38b91c1d57344fbdcf4d66d864bd5c7f848348a535e031fe17cd10355
diff --git a/regress/unittests/sshkey/testdata/rsa_1.param.p b/regress/unittests/sshkey/testdata/rsa_1.param.p
new file mode 100644
index 0000000..92c064b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.param.p
@@ -0,0 +1 @@
+00d36bda3a83f35bdb392f26afb4e124398afa997565da7998b1cf55ed24a82a44ba0cc67cbcd44fcb69e78a5df340084d
diff --git a/regress/unittests/sshkey/testdata/rsa_1.param.q b/regress/unittests/sshkey/testdata/rsa_1.param.q
new file mode 100644
index 0000000..f19e1b7
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.param.q
@@ -0,0 +1 @@
+00c1c78846101966f1a2708fa49d679d1496ef1ce21cf865c268bf64fe058f2882695a1750037055de1c3984ec2835eb29
diff --git a/regress/unittests/sshkey/testdata/rsa_1.pub b/regress/unittests/sshkey/testdata/rsa_1.pub
new file mode 100644
index 0000000..54517b4
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAYQCgCRjn6a+Etop2pDjHKoxkNUSzcKeBVr1mHPscZwKnyUu78GfIntn3J4mTEuvaPQl4gAlMNi2GzRmTH65840BGipTmw4uRwdVzRPvc9NZthkvVx/hINIpTXgMf4XzRA1U= RSA test key #1
diff --git a/regress/unittests/sshkey/testdata/rsa_1_pw b/regress/unittests/sshkey/testdata/rsa_1_pw
new file mode 100644
index 0000000..c2df771
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1_pw
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,64F8EBAD788B4A84B988458AE466E543
+
+Sce5ZTGCDNjY3mXUZohtyPyR7CFo9zaC4NWRDhYVOYT1l3vOX/ULXvvGo/VtsXOw
+eP+TCKYRKAm9yoOVh0E+MwI1TN4vnS8tuE6H5HJxpsE126Q3wFX1mY3ar+laTbrJ
+3uMm2suNSKSh4p46XRC9XFBnxjxaN7RfbwvAaSckqbNjc++NRDOfbE9QS9VlbPA1
+LxUzjAOhgRtQouaQzh2fwcv2xwq2K53iQch/eKe1BqUyv0v6Xb5SalrZa582c9ax
+W4OErS+NrvpI2DxKmoptM24kGaulRggANh+b6k2ZK5GtkSE00kPSVz30po4oo9vb
+oj1tTPjjlW4AGhiCOJM8EGpBJQztGzOCrOLT9bLL0GKE8m3MuwD5+xg/mWAylVnI
+a4LB20Nv9q8yv+6gKgDuMMVdnQit2NEN/s/vW9XOftDO45DgQkib6UTKi/QfVpNW
+/t2Cdd/NH/JRZuvsq/ywMxHf7r65YZ0Ncgv8oEhvIi0mNRI7i3MIvDB0eo8rFQ8E
+R+hNgVkOQS1XGSPacj0GktvQHvysKqzlAq/LDE2tsb9bVh1R8st99R7nCN0RZ1Fc
+PgQkod7cQluBexoqIPTPYJJzVVF0OYjV1WnLXc4MTcY=
+-----END RSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/rsa_2 b/regress/unittests/sshkey/testdata/rsa_2
new file mode 100644
index 0000000..9ab9fa4
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpgIBAAKCAQEA48Cz/hGQvEfUsgObwAZo73nBa/aplYHvUuFJgcTJOXXWRmqI
+St4S2aA2YRZ/vSEo5d8XVTDqQlsxhDFQt1fI72N3rljMut/DLev96MzyCiCUFjP9
+U0c7mYHRh5WZccGBfTD6EcBC3XhDa4znJWsfbyHE0USdYrWjRav37p5+//ZQ3F5k
+Nk6d5zw9lvRHyl1T6b7iux375JWYbWVpwc+bpXRIS7EdZNQKkCIhJoUFBWy3O3vg
+7i9leY5tOtbiAAzWR7ccE/3MPKPwK/pZHWftJVPgBUNwrTPR7K/fviUhdMWmV9d3
+Nz4YBru2y87d4HiJte3D0OXAroUnPxDlGtbTfQIDAQABAoIBAQCIUTzqYyUYLH44
+FkTQyIViYKPOtRKHs//Ewac3jstKIyefegAdn5H0xBoIPmkykHhkLgVPLjnogaC/
+mKzRMC/KaOSna+sOJwQxpkCRaKmuOhWovHFxuP8JQFRjLL1tAv84KWpj2Ymr+WGR
+LALluJpV8AZXoxP4kvMormd1YVRuaqR5qpUlOLUDhGWPq+C/KGfe+eMAYARY8yaq
+YKc880Y9Szgp0OH1QVY9vByq0nn61Gt1GsmDSlesjXbKXgeDFp/OQ9Ir5dYn+Z9O
+Owltm3MwfUaDIbHHR/wpoN6+uzFHNuNiqfu8XsrVRhaM9tu3++DwAqGqDgsbwjVV
+2NMqw/lZAoGBAPpbuMcqo7f0xjZY6px6qDRt7drOm7hEbuMeKWbsihMNLlftJ1Hb
+hfHEbnQxCdhSICkNh4GHA6Uw1hg8MFnIEA8wTRt6dHg2VKkko+RlvE2uqL3SYhUk
+yqTtTA6ZQmY8v4hTeNTorsQKlk3o3rExfJnTreNEDB+xNIrMT4GTlywnAoGBAOji
+ksymSgvxEXoyIzKAymsF3K/h8VLgsw1MyPSHsmWzm9q/WvobZN0jc7POL3pADimI
+xdK8KDh6tDYxF+T52za2EgnKZGOcUwPjIK574kgnwz+Jy8aVaamPj9Pp8NCirOLQ
+RJduiQQM86ri7dIUhc4oHBN6EcKnQ4Z6/ZSifrW7AoGBAOGan9MSMIBHmgpFa/1g
+Zo0AdrOTNS4CtO4DMwnlo7LxUM65DZKtQHGSMnqP6jA+KW71GyP0t6s3a+Zg7q0p
+JJebThCx85yUUQwu0WWy69IQz0xm9i3ZfqbKk5wgLX6VxX8iwSMTHtHYPIOukmaY
+kpDH+M1wd4BjnlZpMEgy6KpHAoGBAIIxWFwsgqzWYizsJp0vPvpB1rRFHgJ1N+Qx
+jw6VZfhRRsotvBCii+rMzPwyQnyXntM9cUp0gg/BGUpKe884l4KomsD6ctD1Lbu4
+mCazfzdTc2XsBQ3Jrb5rUb7oxAX/S6OpRw9ZbiPjkb1xC/8sFfnAlqGU1qT5mVhv
+HaCgjzHNAoGBAM9VmCbSUOdIQhS2QgpnFOWjpMblzmLW4zP9GmUt61myf/l6qckb
+qfqL614w2awtzaFCU7mmfjNqg8zcJ01sI2rT+Sxk9pjK2dbrfGq6eyw1JaZDTAiK
+TQRKjwzfIyzecxWQW7PXBYh12G7a82sJMIQdEQ+wCKpOHDZ/BPmGUaSX
+-----END RSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/rsa_2.fp b/regress/unittests/sshkey/testdata/rsa_2.fp
new file mode 100644
index 0000000..b0188f7
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.fp
@@ -0,0 +1 @@
+01:8d:df:4c:ac:4a:94:eb:27:97:cb:94:fd:cb:7a:15
diff --git a/regress/unittests/sshkey/testdata/rsa_2.fp.bb b/regress/unittests/sshkey/testdata/rsa_2.fp.bb
new file mode 100644
index 0000000..eafc066
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.fp.bb
@@ -0,0 +1 @@
+xekar-cohun-vigov-suzus-filiv-vomit-dobor-kimuk-bekop-rinal-hexox
diff --git a/regress/unittests/sshkey/testdata/rsa_2.param.n b/regress/unittests/sshkey/testdata/rsa_2.param.n
new file mode 100644
index 0000000..891f020
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.param.n
@@ -0,0 +1 @@
+00e3c0b3fe1190bc47d4b2039bc00668ef79c16bf6a99581ef52e14981c4c93975d6466a884ade12d9a03661167fbd2128e5df175530ea425b31843150b757c8ef6377ae58ccbadfc32debfde8ccf20a20941633fd53473b9981d187959971c1817d30fa11c042dd78436b8ce7256b1f6f21c4d1449d62b5a345abf7ee9e7efff650dc5e64364e9de73c3d96f447ca5d53e9bee2bb1dfbe495986d6569c1cf9ba574484bb11d64d40a902221268505056cb73b7be0ee2f65798e6d3ad6e2000cd647b71c13fdcc3ca3f02bfa591d67ed2553e0054370ad33d1ecafdfbe252174c5a657d777373e1806bbb6cbcedde07889b5edc3d0e5c0ae85273f10e51ad6d37d
diff --git a/regress/unittests/sshkey/testdata/rsa_2.param.p b/regress/unittests/sshkey/testdata/rsa_2.param.p
new file mode 100644
index 0000000..e0933e1
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.param.p
@@ -0,0 +1 @@
+00fa5bb8c72aa3b7f4c63658ea9c7aa8346deddace9bb8446ee31e2966ec8a130d2e57ed2751db85f1c46e743109d85220290d87818703a530d6183c3059c8100f304d1b7a74783654a924a3e465bc4daea8bdd2621524caa4ed4c0e9942663cbf885378d4e8aec40a964de8deb1317c99d3ade3440c1fb1348acc4f8193972c27
diff --git a/regress/unittests/sshkey/testdata/rsa_2.param.q b/regress/unittests/sshkey/testdata/rsa_2.param.q
new file mode 100644
index 0000000..62fc210
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.param.q
@@ -0,0 +1 @@
+00e8e292cca64a0bf1117a32233280ca6b05dcafe1f152e0b30d4cc8f487b265b39bdabf5afa1b64dd2373b3ce2f7a400e2988c5d2bc28387ab4363117e4f9db36b61209ca64639c5303e320ae7be24827c33f89cbc69569a98f8fd3e9f0d0a2ace2d044976e89040cf3aae2edd21485ce281c137a11c2a743867afd94a27eb5bb
diff --git a/regress/unittests/sshkey/testdata/rsa_2.pub b/regress/unittests/sshkey/testdata/rsa_2.pub
new file mode 100644
index 0000000..9af3bf3
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjwLP+EZC8R9SyA5vABmjvecFr9qmVge9S4UmBxMk5ddZGaohK3hLZoDZhFn+9ISjl3xdVMOpCWzGEMVC3V8jvY3euWMy638Mt6/3ozPIKIJQWM/1TRzuZgdGHlZlxwYF9MPoRwELdeENrjOclax9vIcTRRJ1itaNFq/funn7/9lDcXmQ2Tp3nPD2W9EfKXVPpvuK7HfvklZhtZWnBz5uldEhLsR1k1AqQIiEmhQUFbLc7e+DuL2V5jm061uIADNZHtxwT/cw8o/Ar+lkdZ+0lU+AFQ3CtM9Hsr9++JSF0xaZX13c3PhgGu7bLzt3geIm17cPQ5cCuhSc/EOUa1tN9 RSA test key #2
diff --git a/regress/unittests/sshkey/testdata/rsa_n b/regress/unittests/sshkey/testdata/rsa_n
new file mode 100644
index 0000000..a84a9e2
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_n
@@ -0,0 +1,12 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIByQIBAAJhAKAJGOfpr4S2inakOMcqjGQ1RLNwp4FWvWYc+xxnAqfJS7vwZ8ie
+2fcniZMS69o9CXiACUw2LYbNGZMfrnzjQEaKlObDi5HB1XNE+9z01m2GS9XH+Eg0
+ilNeAx/hfNEDVQIDAQABAmB8O3OtHHhXYskMHqHA4qPHap6hWZN+0RIIQfkhbEng
+bGAxTgeS8tWrinK+zFJwwS3tYmSc8YfT/4gX/DG1nudv+Pjjhwom/HMTiK/Tw4JN
+ZhWCPKB8T1rICkGAtbMq2KECMQDTa9o6g/Nb2zkvJq+04SQ5ivqZdWXaeZixz1Xt
+JKgqRLoMxny81E/LaeeKXfNACE0CMQDBx4hGEBlm8aJwj6SdZ50Ulu8c4hz4ZcJo
+v2T+BY8ogmlaF1ADcFXeHDmE7Cg16ykCMF7zTCIFirERRqBXdof8qSEyupNa9zBk
+deA9ZrDHSsMY9JmyNukzTNblLDinMwzp7QIwUq/O4X6rKDdBhmB08MmuyINjQuLl
+U8UwQLwy3wYGQVXsmInMFbuQmHdYv/R5cBCJAjAquE/FnCRxuI2NEhoqrO3FG0wO
+cByLc/Svz1ct3eGUMabUxfQdi8Ka97gv9CW9EbI=
+-----END RSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/rsa_n_pw b/regress/unittests/sshkey/testdata/rsa_n_pw
new file mode 100644
index 0000000..1f8b01b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_n_pw
@@ -0,0 +1,14 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABAXd4Cj36
+3zRAFUwdBRAs0yAAAAEAAAAAEAAAB3AAAAB3NzaC1yc2EAAAADAQABAAAAYQCgCRjn6a+E
+top2pDjHKoxkNUSzcKeBVr1mHPscZwKnyUu78GfIntn3J4mTEuvaPQl4gAlMNi2GzRmTH6
+5840BGipTmw4uRwdVzRPvc9NZthkvVx/hINIpTXgMf4XzRA1UAAAGQYoRrooXzXUXdgJVU
+6oeuIcZiBeomdRKu5LrGZF3l2TjLy51+OzJI3ML7f61QneTh8YF8p0UIu6hUM14kifbTse
+qPJZPiLcSM0wbqQz/TRsWwC02wNo4nrHOHwLhqog1l5R52+Ac9O3axuA8t5zfqEMbU8tNE
+GR090/TL1dSQ8z9sHa2ofzODqyuNQZRLKWwhVq/auUiaaUYdTi5i5lInVc9iHaEoCvvp0k
+maG34o4GMHrrp857EmhTL7BrOa5VKYnHW9A3eHcf3JvDNR0crt5ER0wvmivPVr4efy9Cln
+sNBCtZ8rvgsABgM6U6DneX92IogICQGT6nRfyttsMXPO6wt0HUTUAXuD90IAjBueJSvMIO
+g5os68pBvL5rDuB2XCasBIJU27f4NnDQ3aPoSzBA+UgluUs5iWP9+FakY4cQ1cH6tMXGDM
+yW/hSSGzLWukKnFj2XX41boSdH53ZJamL3OoM+ApKSKryOvpTGHQexuFdp1jlZbemKZwBM
+5R7E70V2EaRAxqkRzJyHBQtWIoVQ==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/tests.c b/regress/unittests/sshkey/tests.c
new file mode 100644
index 0000000..13f265c
--- /dev/null
+++ b/regress/unittests/sshkey/tests.c
@@ -0,0 +1,27 @@
+/* 	$OpenBSD: tests.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#include <openssl/evp.h>
+
+#include "../test_helper/test_helper.h"
+
+void sshkey_tests(void);
+void sshkey_file_tests(void);
+void sshkey_fuzz_tests(void);
+
+void
+tests(void)
+{
+	OpenSSL_add_all_algorithms();
+	ERR_load_CRYPTO_strings();
+
+	sshkey_tests();
+	sshkey_file_tests();
+	sshkey_fuzz_tests();
+}