Add libtasn1_encoding_fuzzer [skip ci]

Signed-off-by: Tim Rühsen <tim.ruehsen@gmx.de>
diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am
index b215b6c..7b626e3 100644
--- a/fuzz/Makefile.am
+++ b/fuzz/Makefile.am
@@ -32,7 +32,8 @@
 
 FUZZERS = \
  libtasn1_array2tree_fuzzer$(EXEEXT) \
- libtasn1_parser2tree_fuzzer$(EXEEXT)
+ libtasn1_parser2tree_fuzzer$(EXEEXT) \
+ libtasn1_encoding_fuzzer$(EXEEXT)
 
 if FUZZING
   # fuzzing mode, enabled with ./configure --enable-fuzzing
@@ -51,6 +52,7 @@
 
 libtasn1_array2tree_fuzzer_SOURCES = libtasn1_array2tree_fuzzer.c $(MAIN)
 libtasn1_parser2tree_fuzzer_SOURCES = libtasn1_parser2tree_fuzzer.c $(MAIN)
+libtasn1_encoding_fuzzer_SOURCES = libtasn1_encoding_fuzzer.c $(MAIN)
 
 # comment out below to exclude directories/files from the tarball
 dist-hook:
diff --git a/fuzz/libtasn1_encoding_fuzzer.c b/fuzz/libtasn1_encoding_fuzzer.c
new file mode 100644
index 0000000..b1dadca
--- /dev/null
+++ b/fuzz/libtasn1_encoding_fuzzer.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright(c) 2019 Free Software Foundation, Inc.
+ *
+ * This file is part of libtasn1.
+ *
+ * Libtasn1 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libtasn1 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libtasn1.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This fuzzer is testing the combination of asn1_parser2tree(),
+ * asn1_create_element(), asn1_write_value(), asn1_der_coding() and
+ * asn1_der_decoding() with arbitrary input data.
+ *
+ * This is a test for robustness, not for functionality.
+ */
+
+#include <config.h>
+
+#include <assert.h> // assert
+#include <stdlib.h> // malloc, free
+#include <string.h> // strcmp, memcpy
+
+#include "libtasn1.h"
+#include "fuzzer.h"
+
+static const uint8_t *g_data;
+static size_t g_size;
+
+#if defined HAVE_DLFCN_H && defined HAVE_FMEMOPEN
+#include <dlfcn.h>
+#ifdef RTLD_NEXT /* Not defined e.g. on CygWin */
+
+FILE *fopen(const char *pathname, const char *mode) {
+  FILE * (*libc_fopen)(const char *, const char *) =
+    (FILE * (*)(const char *, const char *)) dlsym(RTLD_NEXT, "fopen");
+
+  if (!strcmp(pathname, "pkix.asn"))
+    return fmemopen((void *) g_data, g_size, mode);
+
+  return libc_fopen(pathname, mode);
+}
+#endif
+#endif
+
+uint8_t der[256];
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+	char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+	asn1_node definitions = NULL;
+	asn1_node asn1_element = NULL;
+	uint8_t *value = NULL, *value0 = NULL;
+
+	if (size > 2048) // same as max_len = 1000 in .options file
+		return 0;
+
+	g_data = data;
+	g_size = size;
+
+	int rc = asn1_parser2tree("pkix.asn", &definitions, errorDescription);
+	if (rc != ASN1_SUCCESS)
+		return 0;
+
+	rc = asn1_create_element(definitions, "TEST_TREE.Koko", &asn1_element);
+	if (rc != ASN1_SUCCESS)
+		goto out;
+
+	size_t vlen = size <= 32 ? size : 32;
+	value = malloc(vlen);
+	assert(value);
+	memcpy(value, data, vlen);
+
+	size_t vlen0 = vlen ? vlen - 1 : 0;
+	value0 = malloc(vlen0 + 1);
+	assert(value0);
+	memcpy(value0, data, vlen0);
+	value0[vlen0] = 0;
+
+	asn1_write_value(asn1_element, "seqint", value0, 0);
+	asn1_write_value(asn1_element, "seqint", value, vlen);
+	asn1_write_value(asn1_element, "seqint.?LAST", value0, 0);
+	asn1_write_value(asn1_element, "seqint.?LAST", value, vlen);
+	asn1_write_value(asn1_element, "int", value0, 0);
+	asn1_write_value(asn1_element, "int", value, vlen);
+	asn1_write_value(asn1_element, "str", value0, 0);
+	asn1_write_value(asn1_element, "str", value, vlen);
+	asn1_write_value(asn1_element, "a", value0, 0);
+	asn1_write_value(asn1_element, "a", value, vlen);
+	asn1_write_value(asn1_element, "b", value0, 0);
+	asn1_write_value(asn1_element, "b", value, vlen);
+	asn1_write_value(asn1_element, "c", value0, 0);
+	asn1_write_value(asn1_element, "c", value, vlen);
+	asn1_write_value(asn1_element, "exp", value0, 0);
+	asn1_write_value(asn1_element, "exp", value, vlen);
+
+	asn1_delete_structure(&definitions);
+
+	int der_size = sizeof(der);
+	if (asn1_der_coding(asn1_element, "", der, &der_size, NULL) != ASN1_SUCCESS)
+		goto out;
+
+	asn1_der_decoding(&asn1_element, der, der_size, NULL);
+
+out:
+	asn1_delete_structure(&asn1_element);
+	asn1_delete_structure(&definitions);
+	free(value0);
+	free(value);
+	return 0;
+}
diff --git a/fuzz/libtasn1_encoding_fuzzer.dict b/fuzz/libtasn1_encoding_fuzzer.dict
new file mode 100644
index 0000000..7ea7bca
--- /dev/null
+++ b/fuzz/libtasn1_encoding_fuzzer.dict
@@ -0,0 +1,29 @@
+"TEST_TREE.Koko"
+"TRUE"
+"FALSE"
+"a"
+"b"
+"c"
+"exp"
+"str"
+"int"
+"seqint"
+"?LAST"
+"seqint.?LAST"
+"TEST_TREE"
+"DEFINITIONS"
+"IMPLICIT"
+"TAGS"
+"::="
+"BEGIN"
+"END"
+"Koko"
+"SEQUENCE"
+"OF"
+"INTEGER"
+"OCTET"
+"STRING"
+"EXPLICIT"
+"OPTIONAL"
+"[0]"
+"[10]"
diff --git a/fuzz/libtasn1_encoding_fuzzer.in/Test_encoding.asn b/fuzz/libtasn1_encoding_fuzzer.in/Test_encoding.asn
new file mode 100644
index 0000000..e3c163c
--- /dev/null
+++ b/fuzz/libtasn1_encoding_fuzzer.in/Test_encoding.asn
@@ -0,0 +1,13 @@
+TEST_TREE { }
+DEFINITIONS IMPLICIT TAGS ::=
+BEGIN
+Koko ::= SEQUENCE {
+   seqint SEQUENCE OF INTEGER,
+   int INTEGER,
+   a      [1] OCTET STRING,
+   b      [10] OCTET STRING,
+   c      [100] OCTET STRING,
+   exp    [3] EXPLICIT OCTET STRING OPTIONAL,
+   str OCTET STRING
+}
+END
diff --git a/fuzz/libtasn1_encoding_fuzzer.in/oom-3f825c1dc37e6ec1784e46878612e7e1c6d2310a b/fuzz/libtasn1_encoding_fuzzer.in/oom-3f825c1dc37e6ec1784e46878612e7e1c6d2310a
new file mode 100644
index 0000000..c6e2b77
--- /dev/null
+++ b/fuzz/libtasn1_encoding_fuzzer.in/oom-3f825c1dc37e6ec1784e46878612e7e1c6d2310a
@@ -0,0 +1,7 @@
+TEST_TREE { }
+DEFINITIONS IMPLICIT TAGS ::=
+BEGIN
+Koko ::= SEQUENCE {
+  x ?L
+}
+END