diff options
Diffstat (limited to 'regress/unittests/sshkey/test_fuzz.c')
-rw-r--r-- | regress/unittests/sshkey/test_fuzz.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/regress/unittests/sshkey/test_fuzz.c b/regress/unittests/sshkey/test_fuzz.c new file mode 100644 index 0000000..2fae19d --- /dev/null +++ b/regress/unittests/sshkey/test_fuzz.c @@ -0,0 +1,391 @@ +/* $OpenBSD: test_fuzz.c,v 1.13 2021/12/14 21:25:27 deraadt Exp $ */ +/* + * Fuzz tests for key parsing + * + * Placed in the public domain + */ + +#include "includes.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef WITH_OPENSSL +#include <openssl/bn.h> +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#include <openssl/objects.h> +#ifdef OPENSSL_HAS_NISTP256 +# include <openssl/ec.h> +#endif +#endif + +#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; + u_int fuzzers = FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP | + FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END; + + if (test_is_fast()) + fuzzers &= ~FUZZ_1_BIT_FLIP; + if (test_is_slow()) + fuzzers |= FUZZ_2_BIT_FLIP | FUZZ_2_BYTE_FLIP; + ASSERT_PTR_NE(buf = sshbuf_new(), NULL); + ASSERT_INT_EQ(sshkey_putb(k, buf), 0); + fuzz = fuzz_begin(fuzzers, 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, const char *sig_alg) +{ + struct fuzz *fuzz; + u_char *sig, c[] = "some junk to be signed"; + size_t l; + u_int fuzzers = FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP | FUZZ_2_BYTE_FLIP | + FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END; + + if (test_is_fast()) + fuzzers &= ~FUZZ_2_BYTE_FLIP; + if (test_is_slow()) + fuzzers |= FUZZ_2_BIT_FLIP; + + ASSERT_INT_EQ(sshkey_sign(k, &sig, &l, c, sizeof(c), + sig_alg, NULL, NULL, 0), 0); + ASSERT_SIZE_T_GT(l, 0); + fuzz = fuzz_begin(fuzzers, sig, l); + ASSERT_INT_EQ(sshkey_verify(k, sig, l, c, sizeof(c), NULL, 0, NULL), 0); + free(sig); + TEST_ONERROR(onerror, fuzz); + for(; !fuzz_done(fuzz); fuzz_next(fuzz)) { + /* Ensure 1-bit difference at least */ + if (fuzz_matches_original(fuzz)) + continue; + ASSERT_INT_NE(sshkey_verify(k, fuzz_ptr(fuzz), fuzz_len(fuzz), + c, sizeof(c), NULL, 0, NULL), 0); + } + fuzz_cleanup(fuzz); +} + +#define NUM_FAST_BASE64_TESTS 1024 + +void +sshkey_fuzz_tests(void) +{ + struct sshkey *k1; + struct sshbuf *buf, *fuzzed; + struct fuzz *fuzz; + int r, i; + +#ifdef WITH_OPENSSL + 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, "", &k1, NULL), 0); + sshkey_free(k1); + sshbuf_free(buf); + ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); + TEST_ONERROR(onerror, fuzz); + for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { + r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); + ASSERT_INT_EQ(r, 0); + if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) + sshkey_free(k1); + sshbuf_reset(fuzzed); + if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) + break; + } + 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, "", &k1, NULL), 0); + sshkey_free(k1); + sshbuf_free(buf); + ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); + TEST_ONERROR(onerror, fuzz); + for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { + r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); + ASSERT_INT_EQ(r, 0); + if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) + sshkey_free(k1); + sshbuf_reset(fuzzed); + if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) + break; + } + 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, "", &k1, NULL), 0); + sshkey_free(k1); + sshbuf_free(buf); + ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); + TEST_ONERROR(onerror, fuzz); + for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { + r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); + ASSERT_INT_EQ(r, 0); + if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) + sshkey_free(k1); + sshbuf_reset(fuzzed); + if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) + break; + } + 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, "", &k1, NULL), 0); + sshkey_free(k1); + sshbuf_free(buf); + ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); + TEST_ONERROR(onerror, fuzz); + for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { + r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); + ASSERT_INT_EQ(r, 0); + if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) + sshkey_free(k1); + sshbuf_reset(fuzzed); + if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) + break; + } + sshbuf_free(fuzzed); + fuzz_cleanup(fuzz); + TEST_DONE(); + +#ifdef OPENSSL_HAS_ECC + 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, "", &k1, NULL), 0); + sshkey_free(k1); + sshbuf_free(buf); + ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); + TEST_ONERROR(onerror, fuzz); + for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { + r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); + ASSERT_INT_EQ(r, 0); + if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) + sshkey_free(k1); + sshbuf_reset(fuzzed); + if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) + break; + } + 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, "", &k1, NULL), 0); + sshkey_free(k1); + sshbuf_free(buf); + ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); + TEST_ONERROR(onerror, fuzz); + for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { + r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); + ASSERT_INT_EQ(r, 0); + if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) + sshkey_free(k1); + sshbuf_reset(fuzzed); + if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) + break; + } + sshbuf_free(fuzzed); + fuzz_cleanup(fuzz); + TEST_DONE(); +#endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ + + 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, "", &k1, NULL), 0); + sshkey_free(k1); + sshbuf_free(buf); + ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); + TEST_ONERROR(onerror, fuzz); + for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { + r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); + ASSERT_INT_EQ(r, 0); + if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) + sshkey_free(k1); + sshbuf_reset(fuzzed); + if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) + break; + } + sshbuf_free(fuzzed); + fuzz_cleanup(fuzz); + TEST_DONE(); + +#ifdef WITH_OPENSSL + TEST_START("fuzz RSA public"); + buf = load_file("rsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &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, "", &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(); + +#ifdef OPENSSL_HAS_ECC + TEST_START("fuzz ECDSA public"); + buf = load_file("ecdsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &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(); +#endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ + + TEST_START("fuzz Ed25519 public"); + buf = load_file("ed25519_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &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(); + +#ifdef WITH_OPENSSL + TEST_START("fuzz RSA sig"); + buf = load_file("rsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); + sshbuf_free(buf); + sig_fuzz(k1, "ssh-rsa"); + sshkey_free(k1); + TEST_DONE(); + + TEST_START("fuzz RSA SHA256 sig"); + buf = load_file("rsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); + sshbuf_free(buf); + sig_fuzz(k1, "rsa-sha2-256"); + sshkey_free(k1); + TEST_DONE(); + + TEST_START("fuzz RSA SHA512 sig"); + buf = load_file("rsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); + sshbuf_free(buf); + sig_fuzz(k1, "rsa-sha2-512"); + sshkey_free(k1); + TEST_DONE(); + + TEST_START("fuzz DSA sig"); + buf = load_file("dsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); + sshbuf_free(buf); + sig_fuzz(k1, NULL); + sshkey_free(k1); + TEST_DONE(); + +#ifdef OPENSSL_HAS_ECC + TEST_START("fuzz ECDSA sig"); + buf = load_file("ecdsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); + sshbuf_free(buf); + sig_fuzz(k1, NULL); + sshkey_free(k1); + TEST_DONE(); +#endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ + + TEST_START("fuzz Ed25519 sig"); + buf = load_file("ed25519_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); + sshbuf_free(buf); + sig_fuzz(k1, NULL); + sshkey_free(k1); + TEST_DONE(); + +/* XXX fuzz decoded new-format blobs too */ +/* XXX fuzz XMSS too */ + +} |