You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

391 lines
10 KiB

/* $OpenBSD: test_fuzz.c,v 1.11 2019/11/25 10:32:35 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>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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
#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, 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 */
}