Skip to content

Commit

Permalink
Add fuzzing!
Browse files Browse the repository at this point in the history
Reviewed-by: Emilia Käsper <[email protected]>
  • Loading branch information
benlaurie committed May 7, 2016
1 parent 049f5bb commit c38bb72
Show file tree
Hide file tree
Showing 13 changed files with 765 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ Makefile

# Executables
/apps/openssl
/fuzz/asn1
/fuzz/asn1parse
/fuzz/bignum
/fuzz/bndiv
/fuzz/conf
/fuzz/cms
/fuzz/server
/fuzz/x509
/test/sha256t
/test/sha512t
/test/gost2814789t
Expand Down
24 changes: 24 additions & 0 deletions Configure
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ my @dtls = qw(dtls1 dtls1_2);

my @disablables = (
"afalgeng",
"asan",
"asm",
"async",
"autoalginit",
Expand Down Expand Up @@ -299,6 +300,7 @@ my @disablables = (
"engine",
"err",
"filenames",
"fuzz",
"gost",
"heartbeats",
"hw(-.+)?",
Expand Down Expand Up @@ -337,6 +339,7 @@ my @disablables = (
"threads",
"tls",
"ts",
"ubsan",
"ui",
"unit-test",
"whirlpool",
Expand All @@ -357,14 +360,17 @@ my @deprecated_disablables = (
# All of the following is disabled by default (RC5 was enabled before 0.9.8):

our %disabled = ( # "what" => "comment"
"asan" => "default",
"ec_nistp_64_gcc_128" => "default",
"egd" => "default",
"fuzz" => "default",
"md2" => "default",
"rc5" => "default",
"sctp" => "default",
"ssl-trace" => "default",
"ssl3" => "default",
"ssl3-method" => "default",
"ubsan" => "default",
"unit-test" => "default",
"weak-ssl-ciphers" => "default",
"zlib" => "default",
Expand Down Expand Up @@ -1029,6 +1035,24 @@ if ($disabled{"dynamic-engine"}) {
$config{dynamic_engines} = 1;
}

unless ($disabled{fuzz}) {
push $config{dirs}, "fuzz";
$config{cflags} .= "-fsanitize-coverage=edge,indirect-calls ";
}

unless ($disabled{asan}) {
$config{cflags} .= "-fsanitize=address ";
}

unless ($disabled{ubsan}) {
# -DPEDANTIC or -fnosanitize=aligmnent may also be required on some
# platforms.
$config{cflags} .= "-fsanitize=undefined -fno-sanitize-recover=all ";
}

unless ($disabled{fuzz} && $disabled{asan} && $disabled{ubsan}) {
$config{cflags} .= "-fno-omit-frame-pointer -g ";
}
#
# Platform fix-ups
#
Expand Down
47 changes: 47 additions & 0 deletions fuzz/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# I Can Haz Fuzz?

Or, how to fuzz OpenSSL with libfuzzer.

Starting from a vanilla+OpenSSH server Ubuntu install.

Use Chrome's handy recent build of clang. Older versions may also work.

$ sudo apt-get install git
$ mkdir git-work
$ git clone https://chromium.googlesource.com/chromium/src/tools/clang
$ clang/scripts/update.py

You may want to git pull and re-run the update from time to time.

Update your path:

$ PATH=~/third_party/llvm-build/Release+Asserts/bin/:$PATH

Get and build libFuzzer (there is a git mirror at
https://github.com/llvm-mirror/llvm/tree/master/lib/Fuzzer if you prefer):

$ cd
$ sudo apt-get install subversion
$ mkdir svn-work
$ cd svn-work
$ svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer
$ cd Fuzzer
$ clang++ -c -g -O2 -std=c++11 *.cpp
$ ar r libFuzzer.a *.o
$ ranlib libFuzzer.a

Configure for fuzzing:

$ CC=clang ./config enable-fuzz enable-asan enable-ubsan no-shared
$ sudo apt-get install make
$ LDCMD=clang++ make -j
$ fuzz/helper.py <fuzzer> <arguments>

Where `<fuzzer>` is one of the executables in `fuzz/`. Most fuzzers do not
need any command line arguments, but, for example, `asn1` needs the name of a
data type.

If you get a crash, you should find a corresponding input file in
`fuzz/corpora/<fuzzer>-crash/`. You can reproduce the crash with

$ fuzz/<fuzzer> <crashfile>
86 changes: 86 additions & 0 deletions fuzz/asn1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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.
*/

/*
* Fuzz ASN.1 parsing for various data structures. Specify which on the
* command line:
*
* asn1 <data structure>
*/

#include <stdio.h>
#include <string.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/ec.h>
#include <openssl/ocsp.h>
#include <openssl/pkcs12.h>
#include <openssl/ts.h>
#include <openssl/x509v3.h>
#include "fuzzer.h"

static const ASN1_ITEM *item_type;

int LLVMFuzzerInitialize(int *argc, char ***argv) {
const char *cmd;
OPENSSL_assert(*argc > 1);

cmd = (*argv)[1];
(*argv)[1] = (*argv)[0];
++*argv;
--*argc;

// TODO: make this work like d2i_test.c does, once its decided what the
// common scheme is!
#define Y(t) if (!strcmp(cmd, #t)) item_type = ASN1_ITEM_rptr(t)
#define X(t) else Y(t)

Y(ASN1_SEQUENCE);
X(AUTHORITY_INFO_ACCESS);
X(BIGNUM);
X(ECPARAMETERS);
X(ECPKPARAMETERS);
X(GENERAL_NAME);
X(GENERAL_SUBTREE);
X(NAME_CONSTRAINTS);
X(OCSP_BASICRESP);
X(OCSP_RESPONSE);
X(PKCS12);
X(PKCS12_AUTHSAFES);
X(PKCS12_SAFEBAGS);
X(PKCS7);
X(PKCS7_ATTR_SIGN);
X(PKCS7_ATTR_VERIFY);
X(PKCS7_DIGEST);
X(PKCS7_ENC_CONTENT);
X(PKCS7_ENCRYPT);
X(PKCS7_ENVELOPE);
X(PKCS7_RECIP_INFO);
X(PKCS7_SIGN_ENVELOPE);
X(PKCS7_SIGNED);
X(PKCS7_SIGNER_INFO);
X(POLICY_CONSTRAINTS);
X(POLICY_MAPPINGS);
X(SXNET);
//X(TS_RESP); want to do this, but type is hidden, however d2i exists...
X(X509);
X(X509_CRL);
else
OPENSSL_assert(!"Bad type");

return 0;
}

int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
const uint8_t *b = buf;
ASN1_VALUE *o = ASN1_item_d2i(NULL, &b, len, item_type);
ASN1_item_free(o, item_type);
return 0;
}
29 changes: 29 additions & 0 deletions fuzz/asn1parse.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.
*/

/*
* Fuzz the parser used for dumping ASN.1 using "openssl asn1parse".
*/

#include <stdio.h>
#include <openssl/asn1.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "fuzzer.h"

int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
static BIO *bio_out;

if (bio_out == NULL)
bio_out = BIO_new_file("/dev/null", "w");

(void)ASN1_parse_dump(bio_out, buf, len, 0, 0);
return 0;
}
91 changes: 91 additions & 0 deletions fuzz/bignum.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* 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.
*/

/*
* Confirm that a^b mod c agrees when calculated cleverly vs naively, for
* random a, b and c.
*/

#include <stdio.h>
#include <openssl/bn.h>
#include "fuzzer.h"

int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
int success = 0;
static BN_CTX *ctx;
static BN_MONT_CTX *mont;
static BIGNUM *b1;
static BIGNUM *b2;
static BIGNUM *b3;
static BIGNUM *b4;
static BIGNUM *b5;

if (ctx == NULL) {
b1 = BN_new();
b2 = BN_new();
b3 = BN_new();
b4 = BN_new();
b5 = BN_new();
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;
if (len > 2) {
len -= 3;
l1 = (buf[0] * len) / 255;
++buf;
l2 = (buf[0] * (len - l1)) / 255;
++buf;
l3 = len - l1 - l2;

s1 = buf[0] & 1;
s2 = buf[0] & 2;
s3 = buf[0] & 4;
++buf;
}
OPENSSL_assert(BN_bin2bn(buf, l1, b1) == b1);
BN_set_negative(b1, s1);
OPENSSL_assert(BN_bin2bn(buf + l1, l2, b2) == b2);
BN_set_negative(b2, s2);
OPENSSL_assert(BN_bin2bn(buf + l1 + l2, l3, b3) == b3);
BN_set_negative(b3, s3);

// mod 0 is undefined
if (BN_is_zero(b3)) {
success = 1;
goto done;
}

OPENSSL_assert(BN_mod_exp(b4, b1, b2, b3, ctx));
OPENSSL_assert(BN_mod_exp_simple(b5, b1, b2, b3, ctx));

success = BN_cmp(b4, b5) == 0;
if (!success) {
BN_print_fp(stdout, b1);
putchar('\n');
BN_print_fp(stdout, b2);
putchar('\n');
BN_print_fp(stdout, b3);
putchar('\n');
BN_print_fp(stdout, b4);
putchar('\n');
BN_print_fp(stdout, b5);
putchar('\n');
}

done:
OPENSSL_assert(success);

return 0;
}
Loading

0 comments on commit c38bb72

Please sign in to comment.