Run the fuzzing corpora as tests.
authorBen Laurie <ben@links.org>
Sat, 4 Jun 2016 15:10:49 +0000 (16:10 +0100)
committerBen Laurie <ben@links.org>
Fri, 1 Jul 2016 12:45:45 +0000 (13:45 +0100)
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
16 files changed:
.gitignore
Configure
fuzz/asn1.c
fuzz/asn1parse.c
fuzz/bignum.c
fuzz/bndiv.c
fuzz/build.info
fuzz/build.info.fuzz [new file with mode: 0644]
fuzz/cms.c
fuzz/conf.c
fuzz/ct.c
fuzz/fuzzer.h
fuzz/server.c
fuzz/test-corpus.c [new file with mode: 0644]
test/recipes/05-test_fuzz.t [new file with mode: 0755]
test/testlib/OpenSSL/Test.pm

index b47a348..a7ca425 100644 (file)
@@ -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
index ee0b4a7..17d7063 100755 (executable)
--- 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"));
index 66825f1..4d22eeb 100644 (file)
 #include <openssl/x509v3.h>
 #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;
 }
index 2fe420b..b3a6dab 100644 (file)
 #include <openssl/x509v3.h>
 #include "fuzzer.h"
 
+int FuzzerInitialize(int *argc, char ***argv) {
+    return 1;
+}
+
 int FuzzerTestOneInput(const uint8_t *buf, size_t len) {
     static BIO *bio_out;
 
index 643e6e7..dc722af 100644 (file)
 #include <openssl/bn.h>
 #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;
index 5212811..45a3937 100644 (file)
 #include <openssl/bn.h>
 #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;
index 8f41878..861f4ef 100644 (file)
@@ -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
-
-SOURCE[asn1]=asn1.c driver.c
-INCLUDE[asn1]=../include {- $ex_inc -}
-DEPEND[asn1]=../libcrypto {- $ex_lib -}
-
-SOURCE[asn1parse]=asn1parse.c driver.c
-INCLUDE[asn1parse]=../include {- $ex_inc -}
-DEPEND[asn1parse]=../libcrypto {- $ex_lib -}
-
-SOURCE[bignum]=bignum.c driver.c
-INCLUDE[bignum]=../include {- $ex_inc -}
-DEPEND[bignum]=../libcrypto {- $ex_lib -}
-
-SOURCE[bndiv]=bndiv.c driver.c
-INCLUDE[bndiv]=../include {- $ex_inc -}
-DEPEND[bndiv]=../libcrypto {- $ex_lib -}
-
-SOURCE[cms]=cms.c driver.c
-INCLUDE[cms]=../include {- $ex_inc -}
-DEPEND[cms]=../libcrypto {- $ex_lib -}
-
-SOURCE[conf]=conf.c driver.c
-INCLUDE[conf]=../include {- $ex_inc -}
-DEPEND[conf]=../libcrypto {- $ex_lib -}
-
-SOURCE[crl]=crl.c driver.c
-INCLUDE[crl]=../include {- $ex_inc -}
-DEPEND[crl]=../libcrypto {- $ex_lib -}
-
-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 -}
+{- 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-test]=asn1.c test-corpus.c
+INCLUDE[asn1-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include
+DEPEND[asn1-test]=../libcrypto
+
+SOURCE[asn1parse-test]=asn1parse.c test-corpus.c
+INCLUDE[asn1parse-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include
+DEPEND[asn1parse-test]=../libcrypto
+
+SOURCE[bignum-test]=bignum.c test-corpus.c
+INCLUDE[bignum-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include
+DEPEND[bignum-test]=../libcrypto
+
+SOURCE[bndiv-test]=bndiv.c test-corpus.c
+INCLUDE[bndiv-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include
+DEPEND[bndiv-test]=../libcrypto
+
+SOURCE[cms-test]=cms.c test-corpus.c
+INCLUDE[cms-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include
+DEPEND[cms-test]=../libcrypto
+
+SOURCE[conf-test]=conf.c test-corpus.c
+INCLUDE[conf-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include
+DEPEND[conf-test]=../libcrypto
+
+SOURCE[ct-test]=ct.c test-corpus.c
+INCLUDE[ct-test]="{- rel2abs(catdir($builddir,"../include")) -}" ../include
+DEPEND[ct-test]=../libcrypto
+
+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 (file)
index 0000000..fafc1df
--- /dev/null
@@ -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 -}
index 71f691f..f97173a 100644 (file)
 #include <openssl/cms.h>
 #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;
index d10d6c7..a76068d 100644 (file)
 #include <openssl/conf.h>
 #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);
 
index dbb7ab4..5dc47f1 100644 (file)
--- a/fuzz/ct.c
+++ b/fuzz/ct.c
 #include <openssl/ct.h>
 #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);
index 289aee2..04d605d 100644 (file)
@@ -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);
index 7b376c1..34c7734 100644 (file)
@@ -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 <openssl/rand.h>
@@ -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 (file)
index 0000000..ccad369
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <openssl/crypto.h>
+#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 (executable)
index 0000000..f5ae228
--- /dev/null
@@ -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", $_])));
+        }
+    }
+}
index 31f4105..0c3b910 100644 (file)
@@ -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);