From d19d229054fe08bc5f40a87a125076ecd334dee4 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 29 Feb 2012 22:28:30 +1100 Subject: [PATCH] flesh out sshkey tests substantially use new fuzz framework to fuzz private and pubkey parsing test loading of RSA1 keys --- unittests/sshkey/Makefile | 2 +- unittests/sshkey/common.c | 78 +++++++++ unittests/sshkey/common.h | 16 ++ unittests/sshkey/mktestdata.sh | 19 ++ unittests/sshkey/test_file.c | 102 ++++++----- unittests/sshkey/test_fuzz.c | 212 +++++++++++++++++++++++ unittests/sshkey/testdata/rsa1_1.param.n | 1 + unittests/sshkey/testdata/rsa1_2.param.n | 1 + unittests/sshkey/tests.c | 2 + 9 files changed, 386 insertions(+), 47 deletions(-) create mode 100644 unittests/sshkey/common.c create mode 100644 unittests/sshkey/common.h create mode 100644 unittests/sshkey/test_fuzz.c create mode 100644 unittests/sshkey/testdata/rsa1_1.param.n create mode 100644 unittests/sshkey/testdata/rsa1_2.param.n diff --git a/unittests/sshkey/Makefile b/unittests/sshkey/Makefile index 09ea76c..a843ab0 100644 --- a/unittests/sshkey/Makefile +++ b/unittests/sshkey/Makefile @@ -1,7 +1,7 @@ # $OpenBSD$ PROG=test_sshkey -SRCS=tests.c test_sshkey.c test_file.c +SRCS=tests.c test_sshkey.c test_file.c test_fuzz.c common.c REGRESS_TARGETS=run-regress-${PROG} run-regress-${PROG}: ${PROG} diff --git a/unittests/sshkey/common.c b/unittests/sshkey/common.c new file mode 100644 index 0000000..6728858 --- /dev/null +++ b/unittests/sshkey/common.c @@ -0,0 +1,78 @@ +/* $OpenBSD$ */ +/* + * Helpers for key API tests + * + * Placed in the public domain + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "test_helper.h" + +#include "err.h" +#include "authfile.h" +#include "key.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); + 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, sshbuf_ptr(buf)), 0); + sshbuf_free(buf); + return ret; +} + diff --git a/unittests/sshkey/common.h b/unittests/sshkey/common.h new file mode 100644 index 0000000..011e7ae --- /dev/null +++ b/unittests/sshkey/common.h @@ -0,0 +1,16 @@ +/* $OpenBSD$ */ +/* + * 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/unittests/sshkey/mktestdata.sh b/unittests/sshkey/mktestdata.sh index 062c98e..c1be3d9 100755 --- a/unittests/sshkey/mktestdata.sh +++ b/unittests/sshkey/mktestdata.sh @@ -2,6 +2,23 @@ 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" @@ -94,6 +111,8 @@ ssh-keygen -pf rsa_1_pw -N "$PW" ssh-keygen -pf dsa_1_pw -N "$PW" ssh-keygen -pf ecdsa_1_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 diff --git a/unittests/sshkey/test_file.c b/unittests/sshkey/test_file.c index d90d4ff..a91e905 100644 --- a/unittests/sshkey/test_file.c +++ b/unittests/sshkey/test_file.c @@ -28,46 +28,10 @@ #include "key.h" #include "sshbuf.h" +#include "common.h" + void sshkey_file_tests(void); -static struct sshbuf * -load_file(const char *name) -{ - int fd; - struct sshbuf *ret; - u_char *p; - - 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); - /* 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; -} - -static BIGNUM * -load_bignum(const char *name) -{ - BIGNUM *ret = NULL; - struct sshbuf *buf; - - buf = load_file(name); - ASSERT_INT_NE(BN_hex2bn(&ret, sshbuf_ptr(buf)), 0); - sshbuf_free(buf); - return ret; -} - void sshkey_file_tests(void) { @@ -77,9 +41,55 @@ sshkey_file_tests(void) char *cp; TEST_START("load passphrase"); - pw = load_file("pw"); + pw = load_text_file("pw"); TEST_DONE(); + TEST_START("parse RSA1 from private"); + buf = load_file("rsa1_1"); + ASSERT_INT_EQ(sshkey_parse_private(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 RSA from private w/ passphrase"); + buf = load_file("rsa1_1_pw"); + ASSERT_INT_EQ(sshkey_parse_private(buf, 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 RSA 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("RSA 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, sshbuf_ptr(buf)); + sshbuf_free(buf); + TEST_DONE(); + + TEST_START("RSA 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, sshbuf_ptr(buf)); + sshbuf_free(buf); + TEST_DONE(); + + sshkey_free(k1); + TEST_START("parse RSA from private"); buf = load_file("rsa_1"); ASSERT_INT_EQ(sshkey_parse_private(buf, "", "rsa_1", &k1, NULL), 0); @@ -115,7 +125,7 @@ sshkey_file_tests(void) TEST_DONE(); TEST_START("RSA key hex fingerprint"); - buf = load_file("rsa_1.fp"); + 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, sshbuf_ptr(buf)); @@ -123,7 +133,7 @@ sshkey_file_tests(void) TEST_DONE(); TEST_START("RSA key bubblebabble fingerprint"); - buf = load_file("rsa_1.fp.bb"); + 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, sshbuf_ptr(buf)); @@ -167,7 +177,7 @@ sshkey_file_tests(void) TEST_DONE(); TEST_START("DSA key hex fingerprint"); - buf = load_file("dsa_1.fp"); + 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, sshbuf_ptr(buf)); @@ -175,7 +185,7 @@ sshkey_file_tests(void) TEST_DONE(); TEST_START("DSA key bubblebabble fingerprint"); - buf = load_file("dsa_1.fp.bb"); + 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, sshbuf_ptr(buf)); @@ -189,7 +199,7 @@ sshkey_file_tests(void) ASSERT_INT_EQ(sshkey_parse_private(buf, "", "ecdsa_1", &k1, NULL), 0); sshbuf_free(buf); ASSERT_PTR_NE(k1, NULL); - buf = load_file("ecdsa_1.param.curve"); + buf = load_text_file("ecdsa_1.param.curve"); ASSERT_STRING_EQ(sshbuf_ptr(buf), OBJ_nid2sn(k1->ecdsa_nid)); sshbuf_free(buf); a = load_bignum("ecdsa_1.param.priv"); @@ -224,7 +234,7 @@ sshkey_file_tests(void) TEST_DONE(); TEST_START("ECDSA key hex fingerprint"); - buf = load_file("ecdsa_1.fp"); + 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, sshbuf_ptr(buf)); @@ -232,7 +242,7 @@ sshkey_file_tests(void) TEST_DONE(); TEST_START("ECDSA key bubblebabble fingerprint"); - buf = load_file("ecdsa_1.fp.bb"); + 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, sshbuf_ptr(buf)); diff --git a/unittests/sshkey/test_fuzz.c b/unittests/sshkey/test_fuzz.c new file mode 100644 index 0000000..ec40549 --- /dev/null +++ b/unittests/sshkey/test_fuzz.c @@ -0,0 +1,212 @@ +/* $OpenBSD$ */ +/* + * Fuzz tests for key parsing + * + * Placed in the public domain + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "test_helper.h" + +#include "err.h" +#include "authfile.h" +#include "key.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); +} + +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_ptr(buf), sshbuf_len(buf)); + ASSERT_INT_EQ(sshkey_parse_private(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(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_ptr(buf), sshbuf_len(buf)); + ASSERT_INT_EQ(sshkey_parse_public_rsa1(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(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_ptr(buf), sshbuf_len(buf)); + ASSERT_INT_EQ(sshkey_parse_private(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(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_ptr(buf), sshbuf_len(buf)); + ASSERT_INT_EQ(sshkey_parse_private(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(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_ptr(buf), sshbuf_len(buf)); + ASSERT_INT_EQ(sshkey_parse_private(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(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(buf, "", "key", &k1, NULL), 0); + sshbuf_reset(buf); + ASSERT_INT_EQ(sshkey_to_blob_buf(k1, buf), 0); + sshkey_free(k1); + fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP | + FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END, + sshbuf_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); + TEST_DONE(); + + TEST_START("fuzz DSA public"); + buf = load_file("dsa_1"); + ASSERT_INT_EQ(sshkey_parse_private(buf, "", "key", &k1, NULL), 0); + sshbuf_reset(buf); + ASSERT_INT_EQ(sshkey_to_blob_buf(k1, buf), 0); + sshkey_free(k1); + fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP | + FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END, + sshbuf_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); + TEST_DONE(); + + TEST_START("fuzz ECDSA public"); + buf = load_file("ecdsa_1"); + ASSERT_INT_EQ(sshkey_parse_private(buf, "", "key", &k1, NULL), 0); + sshbuf_reset(buf); + ASSERT_INT_EQ(sshkey_to_blob_buf(k1, buf), 0); + sshkey_free(k1); + fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP | + FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END, + sshbuf_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); + TEST_DONE(); + +} diff --git a/unittests/sshkey/testdata/rsa1_1.param.n b/unittests/sshkey/testdata/rsa1_1.param.n new file mode 100644 index 0000000..9f8e4c2 --- /dev/null +++ b/unittests/sshkey/testdata/rsa1_1.param.n @@ -0,0 +1 @@ +00abfdd779a7b421aa2f59e6875eb2e56ef93ccd11e2b7d7bcf777d41194ace1bc37f3917eb6852f2bb3d29e2f5a20d14d1ed7db3f06817559b00b9c117b4eed333933b559d862931dbac64a1d13e2957a9bc2f068caea6d53d5da6abc7abdf6b5 diff --git a/unittests/sshkey/testdata/rsa1_2.param.n b/unittests/sshkey/testdata/rsa1_2.param.n new file mode 100644 index 0000000..090c3de --- /dev/null +++ b/unittests/sshkey/testdata/rsa1_2.param.n @@ -0,0 +1 @@ +00d209461d163422c5a32392d857b5065be026adb011ac017ff22934bca8d73d48f4c21e11ebdb894b1c5627eba0a6fab146d1650327687177890ea55510d46d92d0fff78255786f768c29717293865174d5c3f49cb5e55040c9c9a7fe53a10ce1b304f8c9787b6f72d97fb7df9c0050b8288250a4106b7c90f1c32d6bedfb66ce3510d0c084314683990631471b0d57de6a0ad0c69496bc12abeb0c1d32b8bdf9730ca147f6c2bf74884367bd6c398a9fa48b5050a9cdd802990563f106734c4e711e7c50bb50c06eab3523668af39d35adba88764638961742a85401c4e672c505b73d032560e11eea8469155bf863bb289f56802dca3d433a76efd24cfdfa03 diff --git a/unittests/sshkey/tests.c b/unittests/sshkey/tests.c index 161be2f..361e609 100644 --- a/unittests/sshkey/tests.c +++ b/unittests/sshkey/tests.c @@ -11,6 +11,7 @@ void sshkey_tests(void); void sshkey_file_tests(void); +void sshkey_fuzz_tests(void); void tests(void) @@ -20,4 +21,5 @@ tests(void) sshkey_tests(); sshkey_file_tests(); + sshkey_fuzz_tests(); }