diff --git a/.gitignore b/.gitignore index a6f5bf743a..06549caef7 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/Configure b/Configure index f2909ceae1..52d4f934bc 100755 --- a/Configure +++ b/Configure @@ -266,6 +266,7 @@ my @dtls = qw(dtls1 dtls1_2); my @disablables = ( "afalgeng", + "asan", "asm", "async", "autoalginit", @@ -299,6 +300,7 @@ my @disablables = ( "engine", "err", "filenames", + "fuzz", "gost", "heartbeats", "hw(-.+)?", @@ -337,6 +339,7 @@ my @disablables = ( "threads", "tls", "ts", + "ubsan", "ui", "unit-test", "whirlpool", @@ -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", @@ -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 # diff --git a/fuzz/README.md b/fuzz/README.md new file mode 100644 index 0000000000..948590df93 --- /dev/null +++ b/fuzz/README.md @@ -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 + +Where `` 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/-crash/`. You can reproduce the crash with + + $ fuzz/ diff --git a/fuzz/asn1.c b/fuzz/asn1.c new file mode 100644 index 0000000000..fc129a86b0 --- /dev/null +++ b/fuzz/asn1.c @@ -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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/fuzz/asn1parse.c b/fuzz/asn1parse.c new file mode 100644 index 0000000000..63104fb7d0 --- /dev/null +++ b/fuzz/asn1parse.c @@ -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 +#include +#include +#include +#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; +} diff --git a/fuzz/bignum.c b/fuzz/bignum.c new file mode 100644 index 0000000000..28a439e7d7 --- /dev/null +++ b/fuzz/bignum.c @@ -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 +#include +#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; +} diff --git a/fuzz/bndiv.c b/fuzz/bndiv.c new file mode 100644 index 0000000000..c897de99b5 --- /dev/null +++ b/fuzz/bndiv.c @@ -0,0 +1,101 @@ +/* + * 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 if (d, r) = a / b, then b * d + r == a, and that sign(d) == + * sign(a), and 0 <= r <= b + */ + +#include +#include +#include "fuzzer.h" + +int LLVMFuzzerTestOneInput(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; + + if (ctx == NULL) { + b1 = BN_new(); + b2 = BN_new(); + b3 = BN_new(); + b4 = BN_new(); + 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; + 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). + l1 = ((buf[0] & 0x3f) * len) / 0x3f; + s1 = buf[0] & 0x40; + s2 = buf[0] & 0x80; + ++buf; + l2 = len - l1; + } + 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); + + // divide by 0 is an error + if (BN_is_zero(b2)) { + success = 1; + goto done; + } + + OPENSSL_assert(BN_div(b3, b4, b1, b2, ctx)); + if (BN_is_zero(b1)) + success = BN_is_zero(b3) && BN_is_zero(b4); + else if (BN_is_negative(b1)) + success = (BN_is_negative(b3) != BN_is_negative(b2) || BN_is_zero(b3)) + && (BN_is_negative(b4) || BN_is_zero(b4)); + else + success = (BN_is_negative(b3) == BN_is_negative(b2) || BN_is_zero(b3)) + && (!BN_is_negative(b4) || BN_is_zero(b4)); + OPENSSL_assert(BN_mul(b5, b3, b2, ctx)); + OPENSSL_assert(BN_add(b5, b5, b4)); + + success = success && BN_cmp(b5, b1) == 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'); + printf("%d %d %d %d %d %d %d\n", BN_is_negative(b1), + BN_is_negative(b2), + BN_is_negative(b3), BN_is_negative(b4), BN_is_zero(b4), + BN_is_negative(b3) != BN_is_negative(b2) + && (BN_is_negative(b4) || BN_is_zero(b4)), + BN_cmp(b5, b1)); + puts("----\n"); + } + + done: + OPENSSL_assert(success); + + return 0; +} diff --git a/fuzz/build.info b/fuzz/build.info new file mode 100644 index 0000000000..29d14b390e --- /dev/null +++ b/fuzz/build.info @@ -0,0 +1,29 @@ +PROGRAMS=server asn1 asn1parse cms conf bignum bndiv + +SOURCE[server]=server.c +INCLUDE[server]=../include ../../../svn-work/Fuzzer +DEPEND[server]=../libcrypto ../libssl ../../../svn-work/Fuzzer/libFuzzer + +SOURCE[asn1]=asn1.c +INCLUDE[asn1]=../include ../../../svn-work/Fuzzer +DEPEND[asn1]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer + +SOURCE[asn1parse]=asn1parse.c +INCLUDE[asn1parse]=../include ../../../svn-work/Fuzzer +DEPEND[asn1parse]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer + +SOURCE[cms]=cms.c +INCLUDE[cms]=../include ../../../svn-work/Fuzzer +DEPEND[cms]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer + +SOURCE[conf]=conf.c +INCLUDE[conf]=../include ../../../svn-work/Fuzzer +DEPEND[conf]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer + +SOURCE[bignum]=bignum.c +INCLUDE[bignum]=../include ../../../svn-work/Fuzzer +DEPEND[bignum]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer + +SOURCE[bndiv]=bndiv.c +INCLUDE[bndiv]=../include ../../../svn-work/Fuzzer +DEPEND[bndiv]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer diff --git a/fuzz/cms.c b/fuzz/cms.c new file mode 100644 index 0000000000..7b4fc3d319 --- /dev/null +++ b/fuzz/cms.c @@ -0,0 +1,26 @@ +/* + * 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. + */ + +/* + * Test CMS DER parsing. + */ + +#include +#include +#include "fuzzer.h" + +int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { + 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); + CMS_ContentInfo_free(i); + BIO_free(in); + return 0; +} diff --git a/fuzz/conf.c b/fuzz/conf.c new file mode 100644 index 0000000000..3e3f7f184b --- /dev/null +++ b/fuzz/conf.c @@ -0,0 +1,30 @@ +/* + * 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. + */ + +/* + * Test configuration parsing. + */ + +#include +#include "fuzzer.h" + +int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { + CONF *conf = NCONF_new(NULL); + BIO *in = BIO_new(BIO_s_mem()); + long eline; + + 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); + + return 0; +} diff --git a/fuzz/fuzzer.h b/fuzz/fuzzer.h new file mode 100644 index 0000000000..b3c3428c9b --- /dev/null +++ b/fuzz/fuzzer.h @@ -0,0 +1,12 @@ +/* + * 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. + */ + +int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len); +int LLVMFuzzerInitialize(int *argc, char ***argv); diff --git a/fuzz/helper.py b/fuzz/helper.py new file mode 100755 index 0000000000..75a9e12f0a --- /dev/null +++ b/fuzz/helper.py @@ -0,0 +1,45 @@ +#!/usr/bin/python + +"""Fuzzing helper, creates and uses corpus/crash directories. + +fuzzer.py +""" + +import os +import subprocess +import sys + +FUZZER = sys.argv[1] + +THIS_DIR = os.path.abspath(os.path.dirname(__file__)) +CORPORA_DIR = os.path.abspath(os.path.join(THIS_DIR, "corpora")) + +FUZZER_DIR = os.path.abspath(os.path.join(CORPORA_DIR, FUZZER)) +if not os.path.isdir(FUZZER_DIR): + os.mkdir(FUZZER_DIR) + +corpora = [] + +def _create(d): + dd = os.path.abspath(os.path.join(CORPORA_DIR, d)) + if not os.path.isdir(dd): + os.mkdir(dd) + corpora.append(dd) + +def _add(d): + dd = os.path.abspath(os.path.join(CORPORA_DIR, d)) + if os.path.isdir(dd): + corpora.append(dd) + +def main(): + _create(FUZZER) + _create(FUZZER + "-crash") + _add(FUZZER + "-seed") + + cmd = ([os.path.abspath(os.path.join(THIS_DIR, FUZZER))] + sys.argv[2:] + + ["-artifact_prefix=" + corpora[1] + "/"] + corpora) + print " ".join(cmd) + subprocess.call(cmd) + +if __name__ == "__main__": + main() diff --git a/fuzz/server.c b/fuzz/server.c new file mode 100644 index 0000000000..d3ed1adfe0 --- /dev/null +++ b/fuzz/server.c @@ -0,0 +1,237 @@ +/* + * 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. + */ + +// Shamelessly copied from BoringSSL and converted to C. + +// Test first part of SSL server handshake. + + +#include +#include +#include "fuzzer.h" + +static const uint8_t kCertificateDER[] = { + 0x30, 0x82, 0x02, 0xff, 0x30, 0x82, 0x01, 0xe7, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x11, 0x00, 0xb1, 0x84, 0xee, 0x34, 0x99, 0x98, 0x76, 0xfb, + 0x6f, 0xb2, 0x15, 0xc8, 0x47, 0x79, 0x05, 0x9b, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, + 0x12, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, + 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x35, 0x31, 0x31, 0x30, 0x37, 0x30, 0x30, 0x32, 0x34, 0x35, 0x36, 0x5a, + 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x30, 0x36, 0x30, 0x30, 0x32, 0x34, + 0x35, 0x36, 0x5a, 0x30, 0x12, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xce, 0x47, 0xcb, 0x11, + 0xbb, 0xd2, 0x9d, 0x8e, 0x9e, 0xd2, 0x1e, 0x14, 0xaf, 0xc7, 0xea, 0xb6, + 0xc9, 0x38, 0x2a, 0x6f, 0xb3, 0x7e, 0xfb, 0xbc, 0xfc, 0x59, 0x42, 0xb9, + 0x56, 0xf0, 0x4c, 0x3f, 0xf7, 0x31, 0x84, 0xbe, 0xac, 0x03, 0x9e, 0x71, + 0x91, 0x85, 0xd8, 0x32, 0xbd, 0x00, 0xea, 0xac, 0x65, 0xf6, 0x03, 0xc8, + 0x0f, 0x8b, 0xfd, 0x6e, 0x58, 0x88, 0x04, 0x41, 0x92, 0x74, 0xa6, 0x57, + 0x2e, 0x8e, 0x88, 0xd5, 0x3d, 0xda, 0x14, 0x3e, 0x63, 0x88, 0x22, 0xe3, + 0x53, 0xe9, 0xba, 0x39, 0x09, 0xac, 0xfb, 0xd0, 0x4c, 0xf2, 0x3c, 0x20, + 0xd6, 0x97, 0xe6, 0xed, 0xf1, 0x62, 0x1e, 0xe5, 0xc9, 0x48, 0xa0, 0xca, + 0x2e, 0x3c, 0x14, 0x5a, 0x82, 0xd4, 0xed, 0xb1, 0xe3, 0x43, 0xc1, 0x2a, + 0x59, 0xa5, 0xb9, 0xc8, 0x48, 0xa7, 0x39, 0x23, 0x74, 0xa7, 0x37, 0xb0, + 0x6f, 0xc3, 0x64, 0x99, 0x6c, 0xa2, 0x82, 0xc8, 0xf6, 0xdb, 0x86, 0x40, + 0xce, 0xd1, 0x85, 0x9f, 0xce, 0x69, 0xf4, 0x15, 0x2a, 0x23, 0xca, 0xea, + 0xb7, 0x7b, 0xdf, 0xfb, 0x43, 0x5f, 0xff, 0x7a, 0x49, 0x49, 0x0e, 0xe7, + 0x02, 0x51, 0x45, 0x13, 0xe8, 0x90, 0x64, 0x21, 0x0c, 0x26, 0x2b, 0x5d, + 0xfc, 0xe4, 0xb5, 0x86, 0x89, 0x43, 0x22, 0x4c, 0xf3, 0x3b, 0xf3, 0x09, + 0xc4, 0xa4, 0x10, 0x80, 0xf2, 0x46, 0xe2, 0x46, 0x8f, 0x76, 0x50, 0xbf, + 0xaf, 0x2b, 0x90, 0x1b, 0x78, 0xc7, 0xcf, 0xc1, 0x77, 0xd0, 0xfb, 0xa9, + 0xfb, 0xc9, 0x66, 0x5a, 0xc5, 0x9b, 0x31, 0x41, 0x67, 0x01, 0xbe, 0x33, + 0x10, 0xba, 0x05, 0x58, 0xed, 0x76, 0x53, 0xde, 0x5d, 0xc1, 0xe8, 0xbb, + 0x9f, 0xf1, 0xcd, 0xfb, 0xdf, 0x64, 0x7f, 0xd7, 0x18, 0xab, 0x0f, 0x94, + 0x28, 0x95, 0x4a, 0xcc, 0x6a, 0xa9, 0x50, 0xc7, 0x05, 0x47, 0x10, 0x41, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, + 0xa0, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x0c, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, + 0x30, 0x19, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x12, 0x30, 0x10, 0x82, + 0x0e, 0x66, 0x75, 0x7a, 0x7a, 0x2e, 0x62, 0x6f, 0x72, 0x69, 0x6e, 0x67, + 0x73, 0x73, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x92, + 0xde, 0xef, 0x96, 0x06, 0x7b, 0xff, 0x71, 0x7d, 0x4e, 0xa0, 0x7d, 0xae, + 0xb8, 0x22, 0xb4, 0x2c, 0xf7, 0x96, 0x9c, 0x37, 0x1d, 0x8f, 0xe7, 0xd9, + 0x47, 0xff, 0x3f, 0xe9, 0x35, 0x95, 0x0e, 0xdd, 0xdc, 0x7f, 0xc8, 0x8a, + 0x1e, 0x36, 0x1d, 0x38, 0x47, 0xfc, 0x76, 0xd2, 0x1f, 0x98, 0xa1, 0x36, + 0xac, 0xc8, 0x70, 0x38, 0x0a, 0x3d, 0x51, 0x8d, 0x0f, 0x03, 0x1b, 0xef, + 0x62, 0xa1, 0xcb, 0x2b, 0x4a, 0x8c, 0x12, 0x2b, 0x54, 0x50, 0x9a, 0x6b, + 0xfe, 0xaf, 0xd9, 0xf6, 0xbf, 0x58, 0x11, 0x58, 0x5e, 0xe5, 0x86, 0x1e, + 0x3b, 0x6b, 0x30, 0x7e, 0x72, 0x89, 0xe8, 0x6b, 0x7b, 0xb7, 0xaf, 0xef, + 0x8b, 0xa9, 0x3e, 0xb0, 0xcd, 0x0b, 0xef, 0xb0, 0x0c, 0x96, 0x2b, 0xc5, + 0x3b, 0xd5, 0xf1, 0xc2, 0xae, 0x3a, 0x60, 0xd9, 0x0f, 0x75, 0x37, 0x55, + 0x4d, 0x62, 0xd2, 0xed, 0x96, 0xac, 0x30, 0x6b, 0xda, 0xa1, 0x48, 0x17, + 0x96, 0x23, 0x85, 0x9a, 0x57, 0x77, 0xe9, 0x22, 0xa2, 0x37, 0x03, 0xba, + 0x49, 0x77, 0x40, 0x3b, 0x76, 0x4b, 0xda, 0xc1, 0x04, 0x57, 0x55, 0x34, + 0x22, 0x83, 0x45, 0x29, 0xab, 0x2e, 0x11, 0xff, 0x0d, 0xab, 0x55, 0xb1, + 0xa7, 0x58, 0x59, 0x05, 0x25, 0xf9, 0x1e, 0x3d, 0xb7, 0xac, 0x04, 0x39, + 0x2c, 0xf9, 0xaf, 0xb8, 0x68, 0xfb, 0x8e, 0x35, 0x71, 0x32, 0xff, 0x70, + 0xe9, 0x46, 0x6d, 0x5c, 0x06, 0x90, 0x88, 0x23, 0x48, 0x0c, 0x50, 0xeb, + 0x0a, 0xa9, 0xae, 0xe8, 0xfc, 0xbe, 0xa5, 0x76, 0x94, 0xd7, 0x64, 0x22, + 0x38, 0x98, 0x17, 0xa4, 0x3a, 0xa7, 0x59, 0x9f, 0x1d, 0x3b, 0x75, 0x90, + 0x1a, 0x81, 0xef, 0x19, 0xfb, 0x2b, 0xb7, 0xa7, 0x64, 0x61, 0x22, 0xa4, + 0x6f, 0x7b, 0xfa, 0x58, 0xbb, 0x8c, 0x4e, 0x77, 0x67, 0xd0, 0x5d, 0x58, + 0x76, 0x8a, 0xbb, +}; + +static const uint8_t kRSAPrivateKeyDER[] = { + 0x30, 0x82, 0x04, 0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xce, 0x47, 0xcb, 0x11, 0xbb, 0xd2, 0x9d, 0x8e, 0x9e, 0xd2, 0x1e, 0x14, + 0xaf, 0xc7, 0xea, 0xb6, 0xc9, 0x38, 0x2a, 0x6f, 0xb3, 0x7e, 0xfb, 0xbc, + 0xfc, 0x59, 0x42, 0xb9, 0x56, 0xf0, 0x4c, 0x3f, 0xf7, 0x31, 0x84, 0xbe, + 0xac, 0x03, 0x9e, 0x71, 0x91, 0x85, 0xd8, 0x32, 0xbd, 0x00, 0xea, 0xac, + 0x65, 0xf6, 0x03, 0xc8, 0x0f, 0x8b, 0xfd, 0x6e, 0x58, 0x88, 0x04, 0x41, + 0x92, 0x74, 0xa6, 0x57, 0x2e, 0x8e, 0x88, 0xd5, 0x3d, 0xda, 0x14, 0x3e, + 0x63, 0x88, 0x22, 0xe3, 0x53, 0xe9, 0xba, 0x39, 0x09, 0xac, 0xfb, 0xd0, + 0x4c, 0xf2, 0x3c, 0x20, 0xd6, 0x97, 0xe6, 0xed, 0xf1, 0x62, 0x1e, 0xe5, + 0xc9, 0x48, 0xa0, 0xca, 0x2e, 0x3c, 0x14, 0x5a, 0x82, 0xd4, 0xed, 0xb1, + 0xe3, 0x43, 0xc1, 0x2a, 0x59, 0xa5, 0xb9, 0xc8, 0x48, 0xa7, 0x39, 0x23, + 0x74, 0xa7, 0x37, 0xb0, 0x6f, 0xc3, 0x64, 0x99, 0x6c, 0xa2, 0x82, 0xc8, + 0xf6, 0xdb, 0x86, 0x40, 0xce, 0xd1, 0x85, 0x9f, 0xce, 0x69, 0xf4, 0x15, + 0x2a, 0x23, 0xca, 0xea, 0xb7, 0x7b, 0xdf, 0xfb, 0x43, 0x5f, 0xff, 0x7a, + 0x49, 0x49, 0x0e, 0xe7, 0x02, 0x51, 0x45, 0x13, 0xe8, 0x90, 0x64, 0x21, + 0x0c, 0x26, 0x2b, 0x5d, 0xfc, 0xe4, 0xb5, 0x86, 0x89, 0x43, 0x22, 0x4c, + 0xf3, 0x3b, 0xf3, 0x09, 0xc4, 0xa4, 0x10, 0x80, 0xf2, 0x46, 0xe2, 0x46, + 0x8f, 0x76, 0x50, 0xbf, 0xaf, 0x2b, 0x90, 0x1b, 0x78, 0xc7, 0xcf, 0xc1, + 0x77, 0xd0, 0xfb, 0xa9, 0xfb, 0xc9, 0x66, 0x5a, 0xc5, 0x9b, 0x31, 0x41, + 0x67, 0x01, 0xbe, 0x33, 0x10, 0xba, 0x05, 0x58, 0xed, 0x76, 0x53, 0xde, + 0x5d, 0xc1, 0xe8, 0xbb, 0x9f, 0xf1, 0xcd, 0xfb, 0xdf, 0x64, 0x7f, 0xd7, + 0x18, 0xab, 0x0f, 0x94, 0x28, 0x95, 0x4a, 0xcc, 0x6a, 0xa9, 0x50, 0xc7, + 0x05, 0x47, 0x10, 0x41, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xa8, 0x47, 0xb9, 0x4a, 0x06, 0x47, 0x93, 0x71, 0x3d, 0xef, + 0x7b, 0xca, 0xb4, 0x7c, 0x0a, 0xe6, 0x82, 0xd0, 0xe7, 0x0d, 0xa9, 0x08, + 0xf6, 0xa4, 0xfd, 0xd8, 0x73, 0xae, 0x6f, 0x56, 0x29, 0x5e, 0x25, 0x72, + 0xa8, 0x30, 0x44, 0x73, 0xcf, 0x56, 0x26, 0xb9, 0x61, 0xde, 0x42, 0x81, + 0xf4, 0xf0, 0x1f, 0x5d, 0xcb, 0x47, 0xf2, 0x26, 0xe9, 0xe0, 0x93, 0x28, + 0xa3, 0x10, 0x3b, 0x42, 0x1e, 0x51, 0x11, 0x12, 0x06, 0x5e, 0xaf, 0xce, + 0xb0, 0xa5, 0x14, 0xdd, 0x82, 0x58, 0xa1, 0xa4, 0x12, 0xdf, 0x65, 0x1d, + 0x51, 0x70, 0x64, 0xd5, 0x58, 0x68, 0x11, 0xa8, 0x6a, 0x23, 0xc2, 0xbf, + 0xa1, 0x25, 0x24, 0x47, 0xb3, 0xa4, 0x3c, 0x83, 0x96, 0xb7, 0x1f, 0xf4, + 0x44, 0xd4, 0xd1, 0xe9, 0xfc, 0x33, 0x68, 0x5e, 0xe2, 0x68, 0x99, 0x9c, + 0x91, 0xe8, 0x72, 0xc9, 0xd7, 0x8c, 0x80, 0x20, 0x8e, 0x77, 0x83, 0x4d, + 0xe4, 0xab, 0xf9, 0x74, 0xa1, 0xdf, 0xd3, 0xc0, 0x0d, 0x5b, 0x05, 0x51, + 0xc2, 0x6f, 0xb2, 0x91, 0x02, 0xec, 0xc0, 0x02, 0x1a, 0x5c, 0x91, 0x05, + 0xf1, 0xe3, 0xfa, 0x65, 0xc2, 0xad, 0x24, 0xe6, 0xe5, 0x3c, 0xb6, 0x16, + 0xf1, 0xa1, 0x67, 0x1a, 0x9d, 0x37, 0x56, 0xbf, 0x01, 0xd7, 0x3b, 0x35, + 0x30, 0x57, 0x73, 0xf4, 0xf0, 0x5e, 0xa7, 0xe8, 0x0a, 0xc1, 0x94, 0x17, + 0xcf, 0x0a, 0xbd, 0xf5, 0x31, 0xa7, 0x2d, 0xf7, 0xf5, 0xd9, 0x8c, 0xc2, + 0x01, 0xbd, 0xda, 0x16, 0x8e, 0xb9, 0x30, 0x40, 0xa6, 0x6e, 0xbd, 0xcd, + 0x4d, 0x84, 0x67, 0x4e, 0x0b, 0xce, 0xd5, 0xef, 0xf8, 0x08, 0x63, 0x02, + 0xc6, 0xc7, 0xf7, 0x67, 0x92, 0xe2, 0x23, 0x9d, 0x27, 0x22, 0x1d, 0xc6, + 0x67, 0x5e, 0x66, 0xbf, 0x03, 0xb8, 0xa9, 0x67, 0xd4, 0x39, 0xd8, 0x75, + 0xfa, 0xe8, 0xed, 0x56, 0xb8, 0x81, 0x02, 0x81, 0x81, 0x00, 0xf7, 0x46, + 0x68, 0xc6, 0x13, 0xf8, 0xba, 0x0f, 0x83, 0xdb, 0x05, 0xa8, 0x25, 0x00, + 0x70, 0x9c, 0x9e, 0x8b, 0x12, 0x34, 0x0d, 0x96, 0xcf, 0x0d, 0x98, 0x9b, + 0x8d, 0x9c, 0x96, 0x78, 0xd1, 0x3c, 0x01, 0x8c, 0xb9, 0x35, 0x5c, 0x20, + 0x42, 0xb4, 0x38, 0xe3, 0xd6, 0x54, 0xe7, 0x55, 0xd6, 0x26, 0x8a, 0x0c, + 0xf6, 0x1f, 0xe0, 0x04, 0xc1, 0x22, 0x42, 0x19, 0x61, 0xc4, 0x94, 0x7c, + 0x07, 0x2e, 0x80, 0x52, 0xfe, 0x8d, 0xe6, 0x92, 0x3a, 0x91, 0xfe, 0x72, + 0x99, 0xe1, 0x2a, 0x73, 0x76, 0xb1, 0x24, 0x20, 0x67, 0xde, 0x28, 0xcb, + 0x0e, 0xe6, 0x52, 0xb5, 0xfa, 0xfb, 0x8b, 0x1e, 0x6a, 0x1d, 0x09, 0x26, + 0xb9, 0xa7, 0x61, 0xba, 0xf8, 0x79, 0xd2, 0x66, 0x57, 0x28, 0xd7, 0x31, + 0xb5, 0x0b, 0x27, 0x19, 0x1e, 0x6f, 0x46, 0xfc, 0x54, 0x95, 0xeb, 0x78, + 0x01, 0xb6, 0xd9, 0x79, 0x5a, 0x4d, 0x02, 0x81, 0x81, 0x00, 0xd5, 0x8f, + 0x16, 0x53, 0x2f, 0x57, 0x93, 0xbf, 0x09, 0x75, 0xbf, 0x63, 0x40, 0x3d, + 0x27, 0xfd, 0x23, 0x21, 0xde, 0x9b, 0xe9, 0x73, 0x3f, 0x49, 0x02, 0xd2, + 0x38, 0x96, 0xcf, 0xc3, 0xba, 0x92, 0x07, 0x87, 0x52, 0xa9, 0x35, 0xe3, + 0x0c, 0xe4, 0x2f, 0x05, 0x7b, 0x37, 0xa5, 0x40, 0x9c, 0x3b, 0x94, 0xf7, + 0xad, 0xa0, 0xee, 0x3a, 0xa8, 0xfb, 0x1f, 0x11, 0x1f, 0xd8, 0x9a, 0x80, + 0x42, 0x3d, 0x7f, 0xa4, 0xb8, 0x9a, 0xaa, 0xea, 0x72, 0xc1, 0xe3, 0xed, + 0x06, 0x60, 0x92, 0x37, 0xf9, 0xba, 0xfb, 0x9e, 0xed, 0x05, 0xa6, 0xd4, + 0x72, 0x68, 0x4f, 0x63, 0xfe, 0xd6, 0x10, 0x0d, 0x4f, 0x0a, 0x93, 0xc6, + 0xb9, 0xd7, 0xaf, 0xfd, 0xd9, 0x57, 0x7d, 0xcb, 0x75, 0xe8, 0x93, 0x2b, + 0xae, 0x4f, 0xea, 0xd7, 0x30, 0x0b, 0x58, 0x44, 0x82, 0x0f, 0x84, 0x5d, + 0x62, 0x11, 0x78, 0xea, 0x5f, 0xc5, 0x02, 0x81, 0x81, 0x00, 0x82, 0x0c, + 0xc1, 0xe6, 0x0b, 0x72, 0xf1, 0x48, 0x5f, 0xac, 0xbd, 0x98, 0xe5, 0x7d, + 0x09, 0xbd, 0x15, 0x95, 0x47, 0x09, 0xa1, 0x6c, 0x03, 0x91, 0xbf, 0x05, + 0x70, 0xc1, 0x3e, 0x52, 0x64, 0x99, 0x0e, 0xa7, 0x98, 0x70, 0xfb, 0xf6, + 0xeb, 0x9e, 0x25, 0x9d, 0x8e, 0x88, 0x30, 0xf2, 0xf0, 0x22, 0x6c, 0xd0, + 0xcc, 0x51, 0x8f, 0x5c, 0x70, 0xc7, 0x37, 0xc4, 0x69, 0xab, 0x1d, 0xfc, + 0xed, 0x3a, 0x03, 0xbb, 0xa2, 0xad, 0xb6, 0xea, 0x89, 0x6b, 0x67, 0x4b, + 0x96, 0xaa, 0xd9, 0xcc, 0xc8, 0x4b, 0xfa, 0x18, 0x21, 0x08, 0xb2, 0xa3, + 0xb9, 0x3e, 0x61, 0x99, 0xdc, 0x5a, 0x97, 0x9c, 0x73, 0x6a, 0xb9, 0xf9, + 0x68, 0x03, 0x24, 0x5f, 0x55, 0x77, 0x9c, 0xb4, 0xbe, 0x7a, 0x78, 0x53, + 0x68, 0x48, 0x69, 0x53, 0xc8, 0xb1, 0xf5, 0xbf, 0x98, 0x2d, 0x11, 0x1e, + 0x98, 0xa8, 0x36, 0x50, 0xa0, 0xb1, 0x02, 0x81, 0x81, 0x00, 0x90, 0x88, + 0x30, 0x71, 0xc7, 0xfe, 0x9b, 0x6d, 0x95, 0x37, 0x6d, 0x79, 0xfc, 0x85, + 0xe7, 0x44, 0x78, 0xbc, 0x79, 0x6e, 0x47, 0x86, 0xc9, 0xf3, 0xdd, 0xc6, + 0xec, 0xa9, 0x94, 0x9f, 0x40, 0xeb, 0x87, 0xd0, 0xdb, 0xee, 0xcd, 0x1b, + 0x87, 0x23, 0xff, 0x76, 0xd4, 0x37, 0x8a, 0xcd, 0xb9, 0x6e, 0xd1, 0x98, + 0xf6, 0x97, 0x8d, 0xe3, 0x81, 0x6d, 0xc3, 0x4e, 0xd1, 0xa0, 0xc4, 0x9f, + 0xbd, 0x34, 0xe5, 0xe8, 0x53, 0x4f, 0xca, 0x10, 0xb5, 0xed, 0xe7, 0x16, + 0x09, 0x54, 0xde, 0x60, 0xa7, 0xd1, 0x16, 0x6e, 0x2e, 0xb7, 0xbe, 0x7a, + 0xd5, 0x9b, 0x26, 0xef, 0xe4, 0x0e, 0x77, 0xfa, 0xa9, 0xdd, 0xdc, 0xb9, + 0x88, 0x19, 0x23, 0x70, 0xc7, 0xe1, 0x60, 0xaf, 0x8c, 0x73, 0x04, 0xf7, + 0x71, 0x17, 0x81, 0x36, 0x75, 0xbb, 0x97, 0xd7, 0x75, 0xb6, 0x8e, 0xbc, + 0xac, 0x9c, 0x6a, 0x9b, 0x24, 0x89, 0x02, 0x81, 0x80, 0x5a, 0x2b, 0xc7, + 0x6b, 0x8c, 0x65, 0xdb, 0x04, 0x73, 0xab, 0x25, 0xe1, 0x5b, 0xbc, 0x3c, + 0xcf, 0x5a, 0x3c, 0x04, 0xae, 0x97, 0x2e, 0xfd, 0xa4, 0x97, 0x1f, 0x05, + 0x17, 0x27, 0xac, 0x7c, 0x30, 0x85, 0xb4, 0x82, 0x3f, 0x5b, 0xb7, 0x94, + 0x3b, 0x7f, 0x6c, 0x0c, 0xc7, 0x16, 0xc6, 0xa0, 0xbd, 0x80, 0xb0, 0x81, + 0xde, 0xa0, 0x23, 0xa6, 0xf6, 0x75, 0x33, 0x51, 0x35, 0xa2, 0x75, 0x55, + 0x70, 0x4d, 0x42, 0xbb, 0xcf, 0x54, 0xe4, 0xdb, 0x2d, 0x88, 0xa0, 0x7a, + 0xf2, 0x17, 0xa7, 0xdd, 0x13, 0x44, 0x9f, 0x5f, 0x6b, 0x2c, 0x42, 0x42, + 0x8b, 0x13, 0x4d, 0xf9, 0x5b, 0xf8, 0x33, 0x42, 0xd9, 0x9e, 0x50, 0x1c, + 0x7c, 0xbc, 0xfa, 0x62, 0x85, 0x0b, 0xcf, 0x99, 0xda, 0x9e, 0x04, 0x90, + 0xb2, 0xc6, 0xb2, 0x0a, 0x2a, 0x7c, 0x6d, 0x6a, 0x40, 0xfc, 0xf5, 0x50, + 0x98, 0x46, 0x89, 0x82, 0x40, +}; + +static SSL_CTX *ctx; + +static void Init() { + ctx = SSL_CTX_new(SSLv23_method()); + const uint8_t *bufp = kRSAPrivateKeyDER; + RSA *privkey = d2i_RSAPrivateKey(NULL, &bufp, sizeof(kRSAPrivateKeyDER)); + OPENSSL_assert(privkey != NULL); + EVP_PKEY *pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pkey, privkey); + int 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)); + OPENSSL_assert(cert != NULL); + ret = SSL_CTX_use_certificate(ctx, cert); + OPENSSL_assert(ret == 1); + X509_free(cert); + } + +int LLVMFuzzerTestOneInput(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(); + + // 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()); + SSL_set_bio(server, in, out); + 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. + uint8_t tmp[1024]; + for (;;) { + if (SSL_read(server, tmp, sizeof(tmp)) <= 0) { + break; + } + } + } + SSL_free(server); + return 0; +}