From 90d28f0519427ffc293f880c423d9c4395a6fcd4 Mon Sep 17 00:00:00 2001 From: Ben Laurie Date: Sat, 4 Jun 2016 16:10:49 +0100 Subject: [PATCH] Run the fuzzing corpora as tests. Reviewed-by: Richard Levitte Reviewed-by: Rich Salz --- .gitignore | 9 ++++- Configure | 10 ++--- fuzz/asn1.c | 75 ++++++++++++++++++++---------------- fuzz/asn1parse.c | 4 ++ fuzz/bignum.c | 19 +++++---- fuzz/bndiv.c | 26 ++++++++----- fuzz/build.info | 68 +++++++++++++------------------- fuzz/build.info.fuzz | 43 +++++++++++++++++++++ fuzz/cms.c | 8 +++- fuzz/conf.c | 5 ++- fuzz/ct.c | 4 ++ fuzz/fuzzer.h | 2 +- fuzz/server.c | 40 +++++++++++-------- fuzz/test-corpus.c | 44 +++++++++++++++++++++ test/recipes/05-test_fuzz.t | 33 ++++++++++++++++ test/testlib/OpenSSL/Test.pm | 21 +++++++++- 16 files changed, 290 insertions(+), 121 deletions(-) create mode 100644 fuzz/build.info.fuzz create mode 100644 fuzz/test-corpus.c create mode 100755 test/recipes/05-test_fuzz.t diff --git a/.gitignore b/.gitignore index b47a348bdd..a7ca425168 100644 --- a/.gitignore +++ b/.gitignore @@ -60,14 +60,21 @@ Makefile # Executables /apps/openssl /fuzz/asn1 +/fuzz/asn1-test /fuzz/asn1parse +/fuzz/asn1parse-test /fuzz/bignum +/fuzz/bignum-test /fuzz/bndiv +/fuzz/bndiv-test /fuzz/conf +/fuzz/conf-test /fuzz/cms +/fuzz/cms-test /fuzz/ct +/fuzz/ct-test /fuzz/server -/fuzz/x509 +/fuzz/server-test /test/sha256t /test/sha512t /test/gost2814789t diff --git a/Configure b/Configure index ee0b4a7f42..17d7063dba 100755 --- a/Configure +++ b/Configure @@ -245,7 +245,7 @@ my $default_ranlib; $config{fips}=0; # Top level directories to build -$config{dirs} = [ "crypto", "ssl", "engines", "apps", "test", "tools" ]; +$config{dirs} = [ "crypto", "ssl", "engines", "apps", "test", "tools", "fuzz" ]; # crypto/ subdirectories to build $config{sdirs} = [ "objects", @@ -1046,14 +1046,9 @@ if ($disabled{"dynamic-engine"}) { } unless ($disabled{"fuzz-libfuzzer"}) { - push @{$config{dirs}}, "fuzz"; $config{cflags} .= "-fsanitize-coverage=edge,indirect-calls "; } -unless ($disabled{"fuzz-afl"}) { - push @{$config{dirs}}, "fuzz"; -} - unless ($disabled{asan}) { $config{cflags} .= "-fsanitize=address "; } @@ -1337,6 +1332,9 @@ if ($builder eq "unified") { } my @build_infos = ( [ ".", "build.info" ] ); + push @build_infos, [ "fuzz", "build.info.fuzz" ] + unless $disabled{"fuzz-afl"} && $disabled{"fuzz-libfuzzer"}; + foreach (@{$config{dirs}}) { push @build_infos, [ $_, "build.info" ] if (-f catfile($srcdir, $_, "build.info")); diff --git a/fuzz/asn1.c b/fuzz/asn1.c index 66825f1b2c..4d22eebd63 100644 --- a/fuzz/asn1.c +++ b/fuzz/asn1.c @@ -26,45 +26,52 @@ #include #include "fuzzer.h" -static const ASN1_ITEM *item_type[] = { - ASN1_ITEM_rptr(ASN1_SEQUENCE), - ASN1_ITEM_rptr(AUTHORITY_INFO_ACCESS), - ASN1_ITEM_rptr(BIGNUM), - ASN1_ITEM_rptr(ECPARAMETERS), - ASN1_ITEM_rptr(ECPKPARAMETERS), - ASN1_ITEM_rptr(GENERAL_NAME), - ASN1_ITEM_rptr(GENERAL_SUBTREE), - ASN1_ITEM_rptr(NAME_CONSTRAINTS), - ASN1_ITEM_rptr(OCSP_BASICRESP), - ASN1_ITEM_rptr(OCSP_RESPONSE), - ASN1_ITEM_rptr(PKCS12), - ASN1_ITEM_rptr(PKCS12_AUTHSAFES), - ASN1_ITEM_rptr(PKCS12_SAFEBAGS), - ASN1_ITEM_rptr(PKCS7), - ASN1_ITEM_rptr(PKCS7_ATTR_SIGN), - ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY), - ASN1_ITEM_rptr(PKCS7_DIGEST), - ASN1_ITEM_rptr(PKCS7_ENC_CONTENT), - ASN1_ITEM_rptr(PKCS7_ENCRYPT), - ASN1_ITEM_rptr(PKCS7_ENVELOPE), - ASN1_ITEM_rptr(PKCS7_RECIP_INFO), - ASN1_ITEM_rptr(PKCS7_SIGN_ENVELOPE), - ASN1_ITEM_rptr(PKCS7_SIGNED), - ASN1_ITEM_rptr(PKCS7_SIGNER_INFO), - ASN1_ITEM_rptr(POLICY_CONSTRAINTS), - ASN1_ITEM_rptr(POLICY_MAPPINGS), - ASN1_ITEM_rptr(SXNET), - //ASN1_ITEM_rptr(TS_RESP), want to do this, but type is hidden, however d2i exists... - ASN1_ITEM_rptr(X509), - ASN1_ITEM_rptr(X509_CRL), +static ASN1_ITEM_EXP *item_type[] = { + ASN1_ITEM_ref(ASN1_SEQUENCE), + ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS), + ASN1_ITEM_ref(BIGNUM), + ASN1_ITEM_ref(ECPARAMETERS), + ASN1_ITEM_ref(ECPKPARAMETERS), + ASN1_ITEM_ref(GENERAL_NAME), + ASN1_ITEM_ref(GENERAL_SUBTREE), + ASN1_ITEM_ref(NAME_CONSTRAINTS), + ASN1_ITEM_ref(OCSP_BASICRESP), + ASN1_ITEM_ref(OCSP_RESPONSE), + ASN1_ITEM_ref(PKCS12), + ASN1_ITEM_ref(PKCS12_AUTHSAFES), + ASN1_ITEM_ref(PKCS12_SAFEBAGS), + ASN1_ITEM_ref(PKCS7), + ASN1_ITEM_ref(PKCS7_ATTR_SIGN), + ASN1_ITEM_ref(PKCS7_ATTR_VERIFY), + ASN1_ITEM_ref(PKCS7_DIGEST), + ASN1_ITEM_ref(PKCS7_ENC_CONTENT), + ASN1_ITEM_ref(PKCS7_ENCRYPT), + ASN1_ITEM_ref(PKCS7_ENVELOPE), + ASN1_ITEM_ref(PKCS7_RECIP_INFO), + ASN1_ITEM_ref(PKCS7_SIGN_ENVELOPE), + ASN1_ITEM_ref(PKCS7_SIGNED), + ASN1_ITEM_ref(PKCS7_SIGNER_INFO), + ASN1_ITEM_ref(POLICY_CONSTRAINTS), + ASN1_ITEM_ref(POLICY_MAPPINGS), + ASN1_ITEM_ref(SXNET), + /*ASN1_ITEM_ref(TS_RESP), want to do this, but type is hidden, however d2i exists... */ + ASN1_ITEM_ref(X509), + ASN1_ITEM_ref(X509_CRL), NULL }; +int FuzzerInitialize(int *argc, char ***argv) { + return 1; +} + int FuzzerTestOneInput(const uint8_t *buf, size_t len) { - for (int n = 0; item_type[n] != NULL; ++n) { + int n; + + for (n = 0; item_type[n] != NULL; ++n) { const uint8_t *b = buf; - ASN1_VALUE *o = ASN1_item_d2i(NULL, &b, len, item_type[n]); - ASN1_item_free(o, item_type[n]); + const ASN1_ITEM *i = ASN1_ITEM_ptr(item_type[n]); + ASN1_VALUE *o = ASN1_item_d2i(NULL, &b, len, i); + ASN1_item_free(o, i); } return 0; } diff --git a/fuzz/asn1parse.c b/fuzz/asn1parse.c index 2fe420b140..b3a6dab0ea 100644 --- a/fuzz/asn1parse.c +++ b/fuzz/asn1parse.c @@ -18,6 +18,10 @@ #include #include "fuzzer.h" +int FuzzerInitialize(int *argc, char ***argv) { + return 1; +} + int FuzzerTestOneInput(const uint8_t *buf, size_t len) { static BIO *bio_out; diff --git a/fuzz/bignum.c b/fuzz/bignum.c index 643e6e7c65..dc722af83f 100644 --- a/fuzz/bignum.c +++ b/fuzz/bignum.c @@ -17,8 +17,11 @@ #include #include "fuzzer.h" +int FuzzerInitialize(int *argc, char ***argv) { + return 1; +} + int FuzzerTestOneInput(const uint8_t *buf, size_t len) { - int success = 0; static BN_CTX *ctx; static BN_MONT_CTX *mont; static BIGNUM *b1; @@ -26,6 +29,9 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) { static BIGNUM *b3; static BIGNUM *b4; static BIGNUM *b5; + int success = 0; + size_t l1 = 0, l2 = 0, l3 = 0; + int s1 = 0, s2 = 0, s3 = 0; if (ctx == NULL) { b1 = BN_new(); @@ -36,11 +42,10 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) { ctx = BN_CTX_new(); mont = BN_MONT_CTX_new(); } - // Divide the input into three parts, using the values of the first two - // bytes to choose lengths, which generate b1, b2 and b3. Use three bits - // of the third byte to choose signs for the three numbers. - size_t l1 = 0, l2 = 0, l3 = 0; - int s1 = 0, s2 = 0, s3 = 0; + /* Divide the input into three parts, using the values of the first two + * bytes to choose lengths, which generate b1, b2 and b3. Use three bits + * of the third byte to choose signs for the three numbers. + */ if (len > 2) { len -= 3; l1 = (buf[0] * len) / 255; @@ -61,7 +66,7 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) { OPENSSL_assert(BN_bin2bn(buf + l1 + l2, l3, b3) == b3); BN_set_negative(b3, s3); - // mod 0 is undefined + /* mod 0 is undefined */ if (BN_is_zero(b3)) { success = 1; goto done; diff --git a/fuzz/bndiv.c b/fuzz/bndiv.c index 521281109b..45a3937992 100644 --- a/fuzz/bndiv.c +++ b/fuzz/bndiv.c @@ -17,14 +17,21 @@ #include #include "fuzzer.h" +int FuzzerInitialize(int *argc, char ***argv) { + return 1; +} + int FuzzerTestOneInput(const uint8_t *buf, size_t len) { - int success = 0; static BN_CTX *ctx; static BIGNUM *b1; static BIGNUM *b2; static BIGNUM *b3; static BIGNUM *b4; static BIGNUM *b5; + int success = 0; + size_t l1 = 0, l2 = 0; + /* s1 and s2 will be the signs for b1 and b2. */ + int s1 = 0, s2 = 0; if (ctx == NULL) { b1 = BN_new(); @@ -34,16 +41,15 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) { b5 = BN_new(); ctx = BN_CTX_new(); } - // We are going to split the buffer in two, sizes l1 and l2, giving b1 and - // b2. - size_t l1 = 0, l2 = 0; - // s1 and s2 will be the signs for b1 and b2. - int s1 = 0, s2 = 0; + /* We are going to split the buffer in two, sizes l1 and l2, giving b1 and + * b2. + */ if (len > 0) { --len; - // Use first byte to divide the remaining buffer into 3Fths. I admit - // this disallows some number sizes. If it matters, better ideas are - // welcome (Ben). + /* Use first byte to divide the remaining buffer into 3Fths. I admit + * this disallows some number sizes. If it matters, better ideas are + * welcome (Ben). + */ l1 = ((buf[0] & 0x3f) * len) / 0x3f; s1 = buf[0] & 0x40; s2 = buf[0] & 0x80; @@ -55,7 +61,7 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) { OPENSSL_assert(BN_bin2bn(buf + l1, l2, b2) == b2); BN_set_negative(b2, s2); - // divide by 0 is an error + /* divide by 0 is an error */ if (BN_is_zero(b2)) { success = 1; goto done; diff --git a/fuzz/build.info b/fuzz/build.info index 8f41878825..861f4ef9be 100644 --- a/fuzz/build.info +++ b/fuzz/build.info @@ -1,50 +1,34 @@ -{- use File::Spec::Functions; - our $ex_inc = $withargs{fuzzer_include} && - (file_name_is_absolute($withargs{fuzzer_include}) ? - $withargs{fuzzer_include} : catdir(updir(), $withargs{fuzzer_include})); - our $ex_lib = $withargs{fuzzer_lib} && - (file_name_is_absolute($withargs{fuzzer_lib}) ? - $withargs{fuzzer_lib} : catfile(updir(), $withargs{fuzzer_lib})); - "" --} -PROGRAMS=asn1 asn1parse bignum bndiv cms conf crl ct server x509 +{- use File::Spec::Functions qw/catdir rel2abs/; -} +PROGRAMS=asn1-test asn1parse-test bignum-test bndiv-test cms-test conf-test ct-test server-test -SOURCE[asn1]=asn1.c driver.c -INCLUDE[asn1]=../include {- $ex_inc -} -DEPEND[asn1]=../libcrypto {- $ex_lib -} +SOURCE[asn1-test]=asn1.c test-corpus.c +INCLUDE[asn1-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include +DEPEND[asn1-test]=../libcrypto -SOURCE[asn1parse]=asn1parse.c driver.c -INCLUDE[asn1parse]=../include {- $ex_inc -} -DEPEND[asn1parse]=../libcrypto {- $ex_lib -} +SOURCE[asn1parse-test]=asn1parse.c test-corpus.c +INCLUDE[asn1parse-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include +DEPEND[asn1parse-test]=../libcrypto -SOURCE[bignum]=bignum.c driver.c -INCLUDE[bignum]=../include {- $ex_inc -} -DEPEND[bignum]=../libcrypto {- $ex_lib -} +SOURCE[bignum-test]=bignum.c test-corpus.c +INCLUDE[bignum-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include +DEPEND[bignum-test]=../libcrypto -SOURCE[bndiv]=bndiv.c driver.c -INCLUDE[bndiv]=../include {- $ex_inc -} -DEPEND[bndiv]=../libcrypto {- $ex_lib -} +SOURCE[bndiv-test]=bndiv.c test-corpus.c +INCLUDE[bndiv-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include +DEPEND[bndiv-test]=../libcrypto -SOURCE[cms]=cms.c driver.c -INCLUDE[cms]=../include {- $ex_inc -} -DEPEND[cms]=../libcrypto {- $ex_lib -} +SOURCE[cms-test]=cms.c test-corpus.c +INCLUDE[cms-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include +DEPEND[cms-test]=../libcrypto -SOURCE[conf]=conf.c driver.c -INCLUDE[conf]=../include {- $ex_inc -} -DEPEND[conf]=../libcrypto {- $ex_lib -} +SOURCE[conf-test]=conf.c test-corpus.c +INCLUDE[conf-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include +DEPEND[conf-test]=../libcrypto -SOURCE[crl]=crl.c driver.c -INCLUDE[crl]=../include {- $ex_inc -} -DEPEND[crl]=../libcrypto {- $ex_lib -} +SOURCE[ct-test]=ct.c test-corpus.c +INCLUDE[ct-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include +DEPEND[ct-test]=../libcrypto -SOURCE[ct]=ct.c driver.c -INCLUDE[ct]=../include {- $ex_inc -} -DEPEND[ct]=../libcrypto {- $ex_lib -} - -SOURCE[server]=server.c driver.c -INCLUDE[server]=../include {- $ex_inc -} -DEPEND[server]=../libcrypto ../libssl {- $ex_lib -} - -SOURCE[x509]=x509.c driver.c -INCLUDE[x509]=../include {- $ex_inc -} -DEPEND[x509]=../libcrypto ../libssl {- $ex_lib -} +SOURCE[server-test]=server.c test-corpus.c +INCLUDE[server-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include +DEPEND[server-test]=../libcrypto ../libssl diff --git a/fuzz/build.info.fuzz b/fuzz/build.info.fuzz new file mode 100644 index 0000000000..fafc1dfaca --- /dev/null +++ b/fuzz/build.info.fuzz @@ -0,0 +1,43 @@ +{- use File::Spec::Functions; + our $ex_inc = $withargs{fuzzer_include} && + (file_name_is_absolute($withargs{fuzzer_include}) ? + $withargs{fuzzer_include} : catdir(updir(), $withargs{fuzzer_include})); + our $ex_lib = $withargs{fuzzer_lib} && + (file_name_is_absolute($withargs{fuzzer_lib}) ? + $withargs{fuzzer_lib} : catfile(updir(), $withargs{fuzzer_lib})); + "" +-} + +PROGRAMS=asn1 asn1parse bignum bndiv cms conf ct server + +SOURCE[asn1]=asn1.c driver.c +INCLUDE[asn1]="{- rel2abs(catdir($builddir,"../include")) -}" ../include {- $ex_inc -} +DEPEND[asn1]=../libcrypto {- $ex_lib -} + +SOURCE[asn1parse]=asn1parse.c driver.c +INCLUDE[asn1parse]="{- rel2abs(catdir($builddir,"../include")) -}" ../include {- $ex_inc -} +DEPEND[asn1parse]=../libcrypto {- $ex_lib -} + +SOURCE[bignum]=bignum.c driver.c +INCLUDE[bignum]="{- rel2abs(catdir($builddir,"../include")) -}" ../include {- $ex_inc -} +DEPEND[bignum]=../libcrypto {- $ex_lib -} + +SOURCE[bndiv]=bndiv.c driver.c +INCLUDE[bndiv]="{- rel2abs(catdir($builddir,"../include")) -}" ../include {- $ex_inc -} +DEPEND[bndiv]=../libcrypto {- $ex_lib -} + +SOURCE[cms]=cms.c driver.c +INCLUDE[cms]="{- rel2abs(catdir($builddir,"../include")) -}" ../include {- $ex_inc -} +DEPEND[cms]=../libcrypto {- $ex_lib -} + +SOURCE[conf]=conf.c driver.c +INCLUDE[conf]="{- rel2abs(catdir($builddir,"../include")) -}" ../include {- $ex_inc -} +DEPEND[conf]=../libcrypto {- $ex_lib -} + +SOURCE[ct]=ct.c driver.c +INCLUDE[ct]="{- rel2abs(catdir($builddir,"../include")) -}" ../include {- $ex_inc -} +DEPEND[ct]=../libcrypto {- $ex_lib -} + +SOURCE[server]=server.c driver.c +INCLUDE[server]="{- rel2abs(catdir($builddir,"../include")) -}" ../include {- $ex_inc -} +DEPEND[server]=../libcrypto ../libssl {- $ex_lib -} diff --git a/fuzz/cms.c b/fuzz/cms.c index 71f691f61b..f97173add3 100644 --- a/fuzz/cms.c +++ b/fuzz/cms.c @@ -16,10 +16,16 @@ #include #include "fuzzer.h" +int FuzzerInitialize(int *argc, char ***argv) { + return 1; +} + int FuzzerTestOneInput(const uint8_t *buf, size_t len) { + CMS_ContentInfo *i; BIO *in = BIO_new(BIO_s_mem()); + OPENSSL_assert((size_t)BIO_write(in, buf, len) == len); - CMS_ContentInfo *i = d2i_CMS_bio(in, NULL); + i = d2i_CMS_bio(in, NULL); CMS_ContentInfo_free(i); BIO_free(in); return 0; diff --git a/fuzz/conf.c b/fuzz/conf.c index d10d6c7f33..a76068dd74 100644 --- a/fuzz/conf.c +++ b/fuzz/conf.c @@ -15,6 +15,10 @@ #include #include "fuzzer.h" +int FuzzerInitialize(int *argc, char ***argv) { + return 1; +} + int FuzzerTestOneInput(const uint8_t *buf, size_t len) { CONF *conf = NCONF_new(NULL); BIO *in = BIO_new(BIO_s_mem()); @@ -22,7 +26,6 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) { OPENSSL_assert((size_t)BIO_write(in, buf, len) == len); NCONF_load_bio(conf, in, &eline); - //NCONF_dump_fp(conf, stdout); NCONF_free(conf); BIO_free(in); diff --git a/fuzz/ct.c b/fuzz/ct.c index dbb7ab4872..5dc47f1f15 100644 --- a/fuzz/ct.c +++ b/fuzz/ct.c @@ -16,6 +16,10 @@ #include #include "fuzzer.h" +int FuzzerInitialize(int *argc, char ***argv) { + return 1; +} + int FuzzerTestOneInput(const uint8_t *buf, size_t len) { const uint8_t **pp = &buf; STACK_OF(SCT) *scts = d2i_SCT_LIST(NULL, pp, len); diff --git a/fuzz/fuzzer.h b/fuzz/fuzzer.h index 289aee2f60..04d605d79a 100644 --- a/fuzz/fuzzer.h +++ b/fuzz/fuzzer.h @@ -9,4 +9,4 @@ */ int FuzzerTestOneInput(const uint8_t *buf, size_t len); -__attribute__((weak)) int FuzzerInitialize(int *argc, char ***argv); +int FuzzerInitialize(int *argc, char ***argv); diff --git a/fuzz/server.c b/fuzz/server.c index 7b376c1abb..34c77340e8 100644 --- a/fuzz/server.c +++ b/fuzz/server.c @@ -8,9 +8,9 @@ * or in the file LICENSE in the source distribution. */ -// Shamelessly copied from BoringSSL and converted to C. +/* Shamelessly copied from BoringSSL and converted to C. */ -// Test first part of SSL server handshake. +/* Test first part of SSL server handshake. */ #include @@ -190,33 +190,39 @@ static const uint8_t kRSAPrivateKeyDER[] = { static SSL_CTX *ctx; -static void Init() { - ctx = SSL_CTX_new(SSLv23_method()); +int FuzzerInitialize(int *argc, char ***argv) { const uint8_t *bufp = kRSAPrivateKeyDER; - RSA *privkey = d2i_RSAPrivateKey(NULL, &bufp, sizeof(kRSAPrivateKeyDER)); + RSA *privkey; + EVP_PKEY *pkey; + int ret; + X509 *cert; + + ctx = SSL_CTX_new(SSLv23_method()); + privkey = d2i_RSAPrivateKey(NULL, &bufp, sizeof(kRSAPrivateKeyDER)); OPENSSL_assert(privkey != NULL); - EVP_PKEY *pkey = EVP_PKEY_new(); + pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(pkey, privkey); - int ret = SSL_CTX_use_PrivateKey(ctx, pkey); + ret = SSL_CTX_use_PrivateKey(ctx, pkey); OPENSSL_assert(ret == 1); EVP_PKEY_free(pkey); bufp = kCertificateDER; - X509 *cert = d2i_X509(NULL, &bufp, sizeof(kCertificateDER)); + cert = d2i_X509(NULL, &bufp, sizeof(kCertificateDER)); OPENSSL_assert(cert != NULL); ret = SSL_CTX_use_certificate(ctx, cert); OPENSSL_assert(ret == 1); X509_free(cert); - } + + return 1; +} int FuzzerTestOneInput(const uint8_t *buf, size_t len) { - if (ctx == NULL) - Init(); - // TODO: make this work for OpenSSL. There's a PREDICT define that may do - // the job. - // TODO: use the ossltest engine (optionally?) to disable crypto checks. - //RAND_reset_for_fuzzing(); + /* TODO: make this work for OpenSSL. There's a PREDICT define that may do + * the job. + * TODO: use the ossltest engine (optionally?) to disable crypto checks. + * RAND_reset_for_fuzzing(); + */ - // This only fuzzes the initial flow from the client so far. + /* This only fuzzes the initial flow from the client so far. */ SSL *server = SSL_new(ctx); BIO *in = BIO_new(BIO_s_mem()); BIO *out = BIO_new(BIO_s_mem()); @@ -224,7 +230,7 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) { SSL_set_accept_state(server); OPENSSL_assert((size_t)BIO_write(in, buf, len) == len); if (SSL_do_handshake(server) == 1) { - // Keep reading application data until error or EOF. + /* Keep reading application data until error or EOF. */ uint8_t tmp[1024]; for (;;) { if (SSL_read(server, tmp, sizeof(tmp)) <= 0) { diff --git a/fuzz/test-corpus.c b/fuzz/test-corpus.c new file mode 100644 index 0000000000..ccad369faf --- /dev/null +++ b/fuzz/test-corpus.c @@ -0,0 +1,44 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL licenses, (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.openssl.org/source/license.html + * or in the file LICENSE in the source distribution. + */ + +/* + * Given a list of files, run each of them through the fuzzer. Note that + * failure will be indicated by some kind of crash. Switching on things like + * asan improves the test. + */ + +#include +#include +#include +#include +#include "fuzzer.h" + +int main(int argc, char **argv) { + int n; + + FuzzerInitialize(&argc, &argv); + + for (n = 1; n < argc; ++n) { + struct stat st; + FILE *f; + unsigned char *buf; + size_t s; + + stat(argv[n], &st); + f = fopen(argv[n], "rb"); + buf = malloc(st.st_size); + s = fread(buf, 1, st.st_size, f); + OPENSSL_assert(s == (size_t)st.st_size); + FuzzerTestOneInput(buf, s); + free(buf); + fclose(f); + } + return 0; +} diff --git a/test/recipes/05-test_fuzz.t b/test/recipes/05-test_fuzz.t new file mode 100755 index 0000000000..f5ae228de4 --- /dev/null +++ b/test/recipes/05-test_fuzz.t @@ -0,0 +1,33 @@ +#!/usr/bin/env perl +# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; +use warnings; + +use if $^O ne "VMS", 'File::Glob' => qw/glob/; +use OpenSSL::Test qw/:DEFAULT srctop_file/; + +setup("test_fuzz"); + +my @fuzzers = ('asn1', 'asn1parse', 'bignum', 'bndiv', 'cms', 'conf', 'ct', 'server'); +plan tests => scalar @fuzzers; + +foreach my $f (@fuzzers) { + subtest "Fuzzing $f" => sub { + my @files = glob(srctop_file('fuzz', 'corpora', $f, '*')); + push @files, glob(srctop_file('fuzz', 'corpora', "$f-*", '*')); + + plan skip_all => "No corpora for $f-test" unless @files; + + plan tests => scalar @files; + + foreach (@files) { + ok(run(fuzz(["$f-test", $_]))); + } + } +} diff --git a/test/testlib/OpenSSL/Test.pm b/test/testlib/OpenSSL/Test.pm index 31f41057f0..0c3b9104e9 100644 --- a/test/testlib/OpenSSL/Test.pm +++ b/test/testlib/OpenSSL/Test.pm @@ -16,7 +16,8 @@ use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = "0.8"; @ISA = qw(Exporter); -@EXPORT = (@Test::More::EXPORT, qw(setup indir app perlapp test perltest run)); +@EXPORT = (@Test::More::EXPORT, qw(setup indir app fuzz perlapp test perltest + run)); @EXPORT_OK = (@Test::More::EXPORT_OK, qw(bldtop_dir bldtop_file srctop_dir srctop_file pipe with cmdstr quotify)); @@ -285,6 +286,13 @@ sub app { return __build_cmd($num, \&__apps_file, $cmd, %opts); } } +sub fuzz { + my $cmd = shift; + my %opts = @_; + return sub { my $num = shift; + return __build_cmd($num, \&__fuzz_file, $cmd, %opts); } +} + sub test { my $cmd = shift; my %opts = @_; @@ -701,6 +709,8 @@ sub __env { $directories{BLDTOP} = $ENV{BLDTOP} || $ENV{TOP}; $directories{BLDAPPS} = $ENV{BIN_D} || __bldtop_dir("apps"); $directories{SRCAPPS} = __srctop_dir("apps"); + $directories{BLDFUZZ} = __bldtop_dir("fuzz"); + $directories{SRCFUZZ} = __srctop_dir("fuzz"); $directories{BLDTEST} = $ENV{TEST_D} || __bldtop_dir("test"); $directories{SRCTEST} = __srctop_dir("test"); $directories{RESULTS} = $ENV{RESULT_D} || $directories{BLDTEST}; @@ -778,6 +788,15 @@ sub __apps_file { return $f; } +sub __fuzz_file { + BAIL_OUT("Must run setup() first") if (! $test_name); + + my $f = pop; + $f = catfile($directories{BLDFUZZ},@_,$f . __exeext()); + $f = catfile($directories{SRCFUZZ},@_,$f) unless -x $f; + return $f; +} + sub __perlapps_file { BAIL_OUT("Must run setup() first") if (! $test_name);