Unverified Commit a5fbd258 authored by Mouse's avatar Mouse Committed by GitHub

Merge pull request #42 from vlm/master

Merging minor security fix (#318)
parents 5b314f76 f8b6e73a
...@@ -34,8 +34,11 @@ stamp-h* ...@@ -34,8 +34,11 @@ stamp-h*
# /asn1c/ # /asn1c/
/asn1c/asn1c /asn1c/asn1c
/asn1c/unber
/asn1c/enber # /asn1c-tools
/asn1-tools/enber/enber
/asn1-tools/unber/unber
/asn1-tools/unber/check_unber
# /skeletons # /skeletons
/skeletons/check-* /skeletons/check-*
......
...@@ -4,8 +4,10 @@ Bartosz Marcinkiewicz <bma@megawatt.com.pl> ...@@ -4,8 +4,10 @@ Bartosz Marcinkiewicz <bma@megawatt.com.pl>
Bent Nicolaisen <BN@JAI.com> Bent Nicolaisen <BN@JAI.com>
Bi-Ruei, Chiu <biruei.chiu@gmail.com> Bi-Ruei, Chiu <biruei.chiu@gmail.com>
Daniele Varrazzo <daniele.varrazzo@gmail.com> Daniele Varrazzo <daniele.varrazzo@gmail.com>
Dave Cridland <dave@cridland.net>
Denis Filatov (DanyaFilatov @ github) Denis Filatov (DanyaFilatov @ github)
daa @ github daa @ github
Eric Sesterhenn <eric.sesterhenn@x41-dsec.de>
Erika Thorsen (akire @ github) Erika Thorsen (akire @ github)
gareins @ github gareins @ github
johvik @ github johvik @ github
......
...@@ -24,18 +24,22 @@ ...@@ -24,18 +24,22 @@
* uper_encode() API got new argument (breaks API compatibility). * uper_encode() API got new argument (breaks API compatibility).
* asn1c -gen-XXX flags are deprecated. Use -no-gen-XXX to disable codecs. * asn1c -gen-XXX flags are deprecated. Use -no-gen-XXX to disable codecs.
FIXES: FIXES IN COMPILER-GENERATED OUTPUT:
* CVE-2017-12966 verified not present. * Fix incomplete (failed) CHOICE XER decoding memory leak.
* Fix incomplete (failed) CHOICE XER decoding memory leak. (Severity: medium; Security impact: medium)
(Severity: medium; Security impact: medium) * Fix REAL type overwrite conversion memory leak.
* Fix REAL type overwrite conversion memory leak. (Severity: low; Security impact: medium)
(Severity: low; Security impact: medium) * Fix UPER string decoding constrained only by lower bound > 0
* Fix UPER string decoding constrained only by lower bound > 0 (Severity: low; Security impact: none)
(Severity: low; Security impact: none) * Fix UPER decoding of large [bit-]strings of size a multiple of 16K
* Fix UPER decoding of large [bit-]strings of size a multiple of 16K (Severity: low; Security impact: none)
(Severity: low; Security impact: none) * Fix XER decoder crash on maliciously constructed ENUMERATED input.
* Fix XER decoder crash on maliciously constructed ENUMERATED input. (Severity: medium; Security impact: medium)
(Severity: medium; Security impact: medium)
FIXES IN TOOLING:
* CVE-2017-12966 verified not present.
* Fix `unber` buffer overrun. Reported by Eric Sesterhenn.
(Severity: low; Security impact: high)
0.9.28: 2017-03-26 0.9.28: 2017-03-26
* PER decoding: avoid memory leak on error. By github.com/simo5 * PER decoding: avoid memory leak on error. By github.com/simo5
......
...@@ -8,8 +8,8 @@ SUBDIRS = \ ...@@ -8,8 +8,8 @@ SUBDIRS = \
libasn1common libasn1parser \ libasn1common libasn1parser \
libasn1fix libasn1print \ libasn1fix libasn1print \
libasn1compiler \ libasn1compiler \
asn1c skeletons tests \ asn1-tools asn1c skeletons \
examples doc tests examples doc
docsdir = $(datadir)/doc/asn1c docsdir = $(datadir)/doc/asn1c
......
@CODE_COVERAGE_RULES@
SUBDIRS=unber enber
AM_CFLAGS = @ADD_CFLAGS@
AM_CPPFLAGS = -I${top_srcdir}/skeletons
dist_check_SCRIPTS = check-xxber.sh
TESTS_ENVIRONMENT= builddir=${builddir}
TESTS = $(dist_check_SCRIPTS)
CLEANFILES = .check-xxber.*.tmp
unber - The ASN.1 BER Decoder
enber - Reverse unber(1) output back into BER
...@@ -3,6 +3,10 @@ ...@@ -3,6 +3,10 @@
ORIG="./.check-xxber.orig.$$.tmp" ORIG="./.check-xxber.orig.$$.tmp"
TEST="./.check-xxber.test.$$.tmp" TEST="./.check-xxber.test.$$.tmp"
builddir=${builddir:-.}
ENBER=${builddir}/enber/enber
UNBER=${builddir}/unber/unber
# Test diff(1) capabilities # Test diff(1) capabilities
diff -a . . 2>/dev/null && diffArgs="-a" # Assume text files diff -a . . 2>/dev/null && diffArgs="-a" # Assume text files
diff -u . . 2>/dev/null && diffArgs="$diffArgs -u" # Unified diff output diff -u . . 2>/dev/null && diffArgs="$diffArgs -u" # Unified diff output
...@@ -23,7 +27,7 @@ cat<<EOM > $ORIG ...@@ -23,7 +27,7 @@ cat<<EOM > $ORIG
</I O="32" T="[UNIVERSAL 0]" TL="2" L="4"> </I O="32" T="[UNIVERSAL 0]" TL="2" L="4">
EOM EOM
./enber $ORIG | ./unber -p -i 0 - > $TEST 2>&1 ${ENBER} $ORIG | ${UNBER} -p -i 0 - > $TEST 2>&1
diff $diffArgs "$ORIG" "$TEST" >/dev/null 2>&1 diff $diffArgs "$ORIG" "$TEST" >/dev/null 2>&1
diffExitCode=$? diffExitCode=$?
...@@ -36,7 +40,7 @@ fi ...@@ -36,7 +40,7 @@ fi
echo '</I O="34" T="[UNIVERSAL 0]" TL="2" L="36">' >> $ORIG echo '</I O="34" T="[UNIVERSAL 0]" TL="2" L="36">' >> $ORIG
# Try trancoding again # Try trancoding again
./enber $ORIG | ./unber -p -i 0 - > $TEST 2>&1 ${ENBER} $ORIG | ${UNBER} -p -i 0 - > $TEST 2>&1
diff $diffArgs "$ORIG" "$TEST" diff $diffArgs "$ORIG" "$TEST"
diffExitCode=$? diffExitCode=$?
......
@CODE_COVERAGE_RULES@
AM_CFLAGS = @ADD_CFLAGS@
AM_CPPFLAGS = \
-I${top_srcdir}/libasn1common \
-I${top_srcdir}/libasn1parser \
-I${top_srcdir}/skeletons
bin_PROGRAMS = enber
/*- /*
* Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved. * Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -22,9 +22,8 @@ ...@@ -22,9 +22,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id$
*/ */
#include "sys-common.h" #include "asn1_common.h"
#include <asn1parser.h> /* For static string tables */ #include <asn1parser.h> /* For static string tables */
......
@CODE_COVERAGE_RULES@
AM_CFLAGS = @ADD_CFLAGS@
AM_CPPFLAGS = \
-I${top_srcdir}/libasn1common \
-I${top_srcdir}/libasn1parser \
-I${top_srcdir}/skeletons
noinst_LTLIBRARIES = libasn1-unber-tool.la
libasn1_unber_tool_la_SOURCES = \
libasn1_unber_tool.c libasn1_unber_tool.h
bin_PROGRAMS = unber
unber_LDADD = libasn1-unber-tool.la \
$(top_builddir)/libasn1common/libasn1common.la
check_PROGRAMS = check_unber
check_unber_CFLAGS = $(TESTSUITE_CFLAGS) $(LIBFUZZER_CFLAGS)
check_unber_LDADD = libasn1-unber-tool.la \
$(top_builddir)/libasn1common/libasn1common.la
dist_check_SCRIPTS=check_unber.sh
# This jump through the shell is needed to run ./check_unber binary with
# proper fuzzing options.
TESTS_ENVIRONMENT= \
ASAN_ENV_FLAGS="@ASAN_ENV_FLAGS@" \
builddir=${builddir}
TESTS= check_unber.sh
#include "asn1_common.h"
#include "libasn1_unber_tool.h"
// An abstraction for getting data from the in-memory buffer.
struct memory_buffer_stream {
input_stream_t istream;
const uint8_t *data;
size_t size;
size_t offset;
};
static int memory_buffer_stream_nextChar(input_stream_t *ibs) {
struct memory_buffer_stream *bs = (struct memory_buffer_stream *)ibs;
if(bs->offset < bs->size) {
return bs->data[bs->offset++];
} else {
return -1;
}
}
static off_t memory_buffer_stream_bytesRead(input_stream_t *ibs) {
struct memory_buffer_stream *bs = (struct memory_buffer_stream *)ibs;
return (off_t)bs->offset;
}
static int
ignore_vprintf(output_stream_t *os, const char *fmt, va_list ap) {
(void)os;
(void)fmt;
(void)ap;
// Ignore all output.
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
int
LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// Read from a memory buffer.
struct memory_buffer_stream mbs;
mbs.istream.nextChar = memory_buffer_stream_nextChar;
mbs.istream.bytesRead = memory_buffer_stream_bytesRead;
mbs.data = Data;
mbs.size = Size;
mbs.offset = 0;
// Do not print anywhere.
struct output_stream nullstream;
nullstream.vprintf = ignore_vprintf;
nullstream.vprintfError = ignore_vprintf;
(void)unber_stream("<fuzzed-input>", &mbs.istream, &nullstream);
return 0;
}
#ifndef ENABLE_LIBFUZZER
int main() {
printf("libfuzzer is not compiled-in, pretend the test went OK.\n");
return 0;
}
#endif
#!/bin/sh
FUZZ_TIME=${FUZZ_TIME:-10}
builddir=${builddir:-.}
env ${ASAN_ENV_FLAGS:-} ${builddir}/check_unber \
-timeout=3 \
-max_total_time=${FUZZ_TIME} \
-max_len=500
/*- /*
* Copyright (c) 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>. * Copyright (c) 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>.
* All rights reserved. * All rights reserved.
* *
...@@ -23,9 +23,9 @@ ...@@ -23,9 +23,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id$
*/ */
#include "sys-common.h" #include "asn1_common.h"
#include "libasn1_unber_tool.h"
#define ASN_DISABLE_PER_SUPPORT 1 #define ASN_DISABLE_PER_SUPPORT 1
#define ASN_DISABLE_OER_SUPPORT 1 #define ASN_DISABLE_OER_SUPPORT 1
...@@ -43,167 +43,75 @@ ...@@ -43,167 +43,75 @@
#include <asn1p_integer.c> #include <asn1p_integer.c>
#include <asn_internal.c> #include <asn_internal.c>
#undef COPYRIGHT
#define COPYRIGHT "Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>\n"
static void usage(const char *av0); /* Print the Usage screen and exit */
static int process(const char *fname); /* Perform the BER decoding */
static int decode_tlv_from_string(const char *datastring);
static int single_type_decoding = 0; /* -1 enables that */ static int single_type_decoding = 0; /* -1 enables that */
static int minimalistic = 0; /* -m enables that */ static int minimalistic = 0; /* -m enables that */
static int pretty_printing = 1; /* -p disables that */ static int pretty_printing = 1; /* -p disables that */
static long skip_bytes = 0; /* -s controls that */ static long skip_bytes = 0; /* -s controls that */
static char indent_bytes[16] = " "; /* -i controls that */ static char indent_bytes[16] = " "; /* -i controls that */
int void set_minimalistic_output(int v) { minimalistic = v; }
main(int ac, char **av) { void set_single_type_decoding(int v) { single_type_decoding = v; }
int ch; /* Command line character */ void set_pretty_printing(int v) { pretty_printing = v; }
int i; /* Index in some loops */ int set_skip_bytes(long v) { if(v < 0) return -1; skip_bytes = v; return 0; }
int set_indent_size(int indent_size) {
/* if(indent_size < 0 || indent_size >= (int)sizeof(indent_bytes)) {
* Process command-line options. return -1;
*/
while((ch = getopt(ac, av, "1hi:mps:t:v")) != -1) switch(ch) {
case '1':
single_type_decoding = 1;
break;
case 'i':
i = atoi(optarg);
if(i >= 0 && i < (int)sizeof(indent_bytes)) {
memset(indent_bytes, ' ', i);
indent_bytes[i] = '\0';
} else {
fprintf(stderr, "-i %s: Invalid indent value\n", optarg);
exit(EX_USAGE);
}
break;
case 'm':
minimalistic = 1;
break;
case 'p':
pretty_printing = 0;
break;
case 's':
skip_bytes = atol(optarg);
if(skip_bytes < 0) {
fprintf(stderr, "-s %s: positive value expected\n", optarg);
exit(EX_USAGE);
}
break;
case 't':
if(decode_tlv_from_string(optarg)) exit(EX_DATAERR);
exit(0);
case 'v':
fprintf(stderr, "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT);
exit(0);
break;
case 'h':
default:
usage(av[0]);
}
/*
* Ensure that there are some input files present.
*/
if(ac > optind) {
ac -= optind;
av += optind;
} else {
fprintf(stderr, "%s: No input files specified\n", av[0]);
exit(1);
}
setvbuf(stdout, 0, _IOLBF, 0);
/*
* Iterate over input files and parse each.
* All syntax trees from all files will be bundled together.
*/
for(i = 0; i < ac; i++) {
if(process(av[i])) exit(EX_DATAERR);
} }
memset(indent_bytes, ' ', indent_size);
indent_bytes[indent_size] = '\0';
return 0; return 0;
} }
/*
* Print the usage screen and exit(EX_USAGE).
*/
static void
usage(const char *av0) {
/* clang-format off */
fprintf(stderr,
"ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT
"Usage: %s [options] [-] [file ...]\n"
"Options:\n"
" -1 Decode only the first BER structure (otherwise, until EOF)\n"
" -i <indent> Amount of spaces for output indentation (default is 4)\n"
" -m Minimalistic mode: print as little as possible\n"
" -p Do not attempt pretty-printing of known ASN.1 types\n"
" -s <skip> Ignore first <skip> bytes of input\n"
" -t <hex-string> Decode the given tag[/length] sequence (e.g. -t \"bf20\")\n"
"\n"
"The XML opening tag format is as follows:\n"
" <tform O=\"off\" T=\"tag\" TL=\"tl_len\" V=\"{Indefinite|v_len}\" [A=\"type\"] [F]>\n"
"Where:\n"
" tform Which form the value is in: constructed (\"C\", \"I\") or primitive (\"P\")\n"
" off Offset of the encoded element in the unber input stream\n"
" tag The tag class and value in human readable form\n"
" tl_len The length of the TL (BER Tag and Length) encoding\n"
" v_len The length of the value (V, encoded by the L), may be \"Indefinite\"\n"
" type Likely name of the underlying ASN.1 type (for [UNIVERSAL n] tags)\n"
" [F] Indicates that the value was reformatted (pretty-printed)\n"
"See the manual page for details\n"
, av0);
/* clang-format on */
exit(EX_USAGE);
}
typedef enum pd_code { typedef enum pd_code {
PD_FAILED = -1, PD_FAILED = -1,
PD_FINISHED = 0, PD_FINISHED = 0,
PD_EOF = 1, PD_EOF = 1,
} pd_code_e; } pd_code_e;
static pd_code_e process_deeper(const char *fname, FILE *fp, static pd_code_e process_deeper(const char *fname, input_stream_t *,
size_t *offset, int level, output_stream_t *os, int level,
ssize_t limit, ber_tlv_len_t *frame_size, ssize_t limit, ber_tlv_len_t *frame_size,
ber_tlv_len_t effective_size, int expect_eoc); ber_tlv_len_t effective_size, int expect_eoc);
static void print_TL(int fin, size_t offset, int level, int constr, static void print_TL(output_stream_t *, int fin, off_t offset, int level,
ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t, int constr, ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t,
ber_tlv_len_t effective_frame_size); ber_tlv_len_t effective_frame_size);
static int print_V(const char *fname, FILE *fp, ber_tlv_tag_t, ber_tlv_len_t); static int print_V(const char *fname, input_stream_t *, output_stream_t *,
ber_tlv_tag_t, ber_tlv_len_t);
static int ibs_getc(input_stream_t *ibs) { return ibs->nextChar(ibs); }
static int __attribute__((format(printf, 2, 3)))
osprintf(output_stream_t *os, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = os->vprintf(os, fmt, ap);
va_end(ap);
return ret;
}
static int __attribute__((format(printf, 2, 3)))
osprintfError(output_stream_t *os, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = os->vprintfError(os, fmt, ap);
va_end(ap);
return ret;
}
/* /*
* Open the file and initiate recursive processing. * Open the file and initiate recursive processing.
*/ */
static int int
process(const char *fname) { unber_stream(const char *fname, input_stream_t *ibs, output_stream_t *os) {
FILE *fp;
pd_code_e pdc; pd_code_e pdc;
size_t offset = 0; /* Stream decoding position */
ber_tlv_len_t frame_size = 0; /* Single frame size */ ber_tlv_len_t frame_size = 0; /* Single frame size */
if(strcmp(fname, "-")) {
fp = fopen(fname, "rb");
if(!fp) {
perror(fname);
return -1;
}
} else {
fp = stdin;
}
/* /*
* Skip the requested amount of bytes. * Skip the requested amount of bytes.
*/ */
for(; offset < (size_t)skip_bytes; offset++) { for(size_t offset = 0; offset < (size_t)skip_bytes; offset++) {
if(fgetc(fp) == -1) { if(ibs_getc(ibs) == -1) {
fprintf(stderr, "%s: input source (%zu bytes) " osprintfError(os,
"has less data than \"-s %ld\" switch " "%s: input source has less data "
"wants to skip\n", "than \"-s %ld\" switch wants to skip\n",
fname, offset, skip_bytes); fname, skip_bytes);
if(fp != stdin) fclose(fp);
return -1; return -1;
} }
} }
...@@ -212,11 +120,9 @@ process(const char *fname) { ...@@ -212,11 +120,9 @@ process(const char *fname) {
* Fetch out BER-encoded data until EOF or error. * Fetch out BER-encoded data until EOF or error.
*/ */
do { do {
pdc = process_deeper(fname, fp, &offset, 0, -1, &frame_size, 0, 0); pdc = process_deeper(fname, ibs, os, 0, -1, &frame_size, 0, 0);
} while(pdc == PD_FINISHED && !single_type_decoding); } while(pdc == PD_FINISHED && !single_type_decoding);
if(fp != stdin) fclose(fp);
if(pdc == PD_FAILED) return -1; if(pdc == PD_FAILED) return -1;
return 0; return 0;
} }
...@@ -225,8 +131,8 @@ process(const char *fname) { ...@@ -225,8 +131,8 @@ process(const char *fname) {
* Process the TLV recursively. * Process the TLV recursively.
*/ */
static pd_code_e static pd_code_e
process_deeper(const char *fname, FILE *fp, size_t *offset, int level, process_deeper(const char *fname, input_stream_t *ibs, output_stream_t *os,
ssize_t limit, ber_tlv_len_t *frame_size, int level, ssize_t limit, ber_tlv_len_t *frame_size,
ber_tlv_len_t effective_size, int expect_eoc) { ber_tlv_len_t effective_size, int expect_eoc) {
unsigned char tagbuf[32]; unsigned char tagbuf[32];
ssize_t tblen = 0; ssize_t tblen = 0;
...@@ -244,22 +150,29 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level, ...@@ -244,22 +150,29 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
if(limit == 0) return PD_FINISHED; if(limit == 0) return PD_FINISHED;
if(limit >= 0 && tblen >= limit) { if(limit >= 0 && tblen >= limit) {
fprintf(stderr, osprintfError(os,
"%s: Too long TL sequence (%ld >= %ld)" "%s: Too long TL sequence (%zd >= %zd) at %lld. "
" at %zu. " "Broken or maliciously constructed file\n",
"Broken or maliciously constructed file\n", fname, tblen, limit, ibs->bytesRead(ibs));
fname, (long)tblen, (long)limit, *offset); return PD_FAILED;
}
if(tblen >= (ssize_t)sizeof(tagbuf)) {
osprintfError(os,
"%s: Too long TL sequence (%zd bytes) at %lld. "
"Broken or maliciously constructed file\n",
fname, tblen, ibs->bytesRead(ibs));
return PD_FAILED; return PD_FAILED;
} }
/* Get the next byte from the input stream */ /* Get the next byte from the input stream */
ch = fgetc(fp); ch = ibs_getc(ibs);
if(ch == -1) { if(ch == -1) {
if(limit > 0 || expect_eoc) { if(limit > 0 || expect_eoc) {
fprintf(stderr, osprintfError(os,
"%s: Unexpected end of file (TL)" "%s: Unexpected end of file (TL)"
" at %zu\n", " at %zu\n",
fname, *offset); fname, (size_t)ibs->bytesRead(ibs));
return PD_FAILED; return PD_FAILED;
} else { } else {
return PD_EOF; return PD_EOF;
...@@ -274,10 +187,10 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level, ...@@ -274,10 +187,10 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
t_len = ber_fetch_tag(tagbuf, tblen, &tlv_tag); t_len = ber_fetch_tag(tagbuf, tblen, &tlv_tag);
switch(t_len) { switch(t_len) {
case -1: case -1:
fprintf(stderr, osprintfError(os,
"%s: Fatal error decoding tag" "%s: Fatal error decoding tag"
" at %zu+%ld\n", " at %zu\n",
fname, *offset, (long)tblen); fname, (size_t)ibs->bytesRead(ibs));
return PD_FAILED; return PD_FAILED;
case 0: case 0:
/* More data expected */ /* More data expected */
...@@ -292,10 +205,10 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level, ...@@ -292,10 +205,10 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
ber_fetch_length(constr, tagbuf + t_len, tblen - t_len, &tlv_len); ber_fetch_length(constr, tagbuf + t_len, tblen - t_len, &tlv_len);
switch(l_len) { switch(l_len) {
case -1: case -1:
fprintf(stderr, osprintfError(os,
"%s: Fatal error decoding value length" "%s: Fatal error decoding value length"
" at %zu\n", " at %zu\n",
fname, *offset + t_len); fname, (size_t)ibs->bytesRead(ibs));
return PD_FAILED; return PD_FAILED;
case 0: case 0:
/* More data expected */ /* More data expected */
...@@ -303,11 +216,17 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level, ...@@ -303,11 +216,17 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
} }
/* Make sure the T & L decoders took exactly the whole buffer */ /* Make sure the T & L decoders took exactly the whole buffer */
assert((t_len + l_len) == tblen); if((t_len + l_len) != tblen) {
osprintfError(os,
"%s: Outer tag length doesn't match inner tag length"
" at %zu\n",
fname, (size_t)ibs->bytesRead(ibs));
return PD_FAILED;
}
if(!expect_eoc || tagbuf[0] || tagbuf[1]) if(!expect_eoc || tagbuf[0] || tagbuf[1])
print_TL(0, *offset, level, constr, tblen, tlv_tag, tlv_len, print_TL(os, 0, ibs->bytesRead(ibs), level, constr, tblen,
effective_size); tlv_tag, tlv_len, effective_size);
if(limit != -1) { if(limit != -1) {
/* If limit is set, account for the TL sequence */ /* If limit is set, account for the TL sequence */
...@@ -315,22 +234,22 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level, ...@@ -315,22 +234,22 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
assert(limit >= 0); assert(limit >= 0);
if(tlv_len > limit) { if(tlv_len > limit) {
fprintf(stderr, osprintfError(os,
"%s: Structure advertizes length (%ld) " "%s: Structure advertizes length (%ld) "
"greater than of a parent container (%ld)\n", "greater than of a parent container (%ld)\n",
fname, (long)tlv_len, (long)limit); fname, (long)tlv_len, (long)limit);
return PD_FAILED; return PD_FAILED;
} }
} }
*offset += t_len + l_len;
*frame_size += t_len + l_len; *frame_size += t_len + l_len;
effective_size += t_len + l_len; effective_size += t_len + l_len;
local_esize += t_len + l_len; local_esize += t_len + l_len;
if(expect_eoc && !tagbuf[0] && !tagbuf[1]) { if(expect_eoc && !tagbuf[0] && !tagbuf[1]) {
/* End of content octets */ /* End of content octets */
print_TL(1, *offset - 2, level - 1, 1, 2, 0, -1, effective_size); print_TL(os, 1, ibs->bytesRead(ibs), level - 1, 1, 2, 0, -1,
effective_size);
return PD_FINISHED; return PD_FINISHED;
} }
...@@ -339,11 +258,11 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level, ...@@ -339,11 +258,11 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
/* /*
* This is a constructed type. Process recursively. * This is a constructed type. Process recursively.
*/ */
printf(">\n"); /* Close the opening tag */ osprintf(os, ">\n"); /* Close the opening tag */
if(tlv_len != -1 && limit != -1) { if(tlv_len != -1 && limit != -1) {
assert(limit >= tlv_len); assert(limit >= tlv_len);
} }
pdc = process_deeper(fname, fp, offset, level + 1, pdc = process_deeper(fname, ibs, os, level + 1,
tlv_len == -1 ? limit : tlv_len, &dec, tlv_len == -1 ? limit : tlv_len, &dec,
t_len + l_len, tlv_len == -1); t_len + l_len, tlv_len == -1);
if(pdc == PD_FAILED) return pdc; if(pdc == PD_FAILED) return pdc;
...@@ -361,20 +280,19 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level, ...@@ -361,20 +280,19 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
} }
} else { } else {
assert(tlv_len >= 0); assert(tlv_len >= 0);
if(print_V(fname, fp, tlv_tag, tlv_len)) return PD_FAILED; if(print_V(fname, ibs, os, tlv_tag, tlv_len)) return PD_FAILED;
if(limit != -1) { if(limit != -1) {
assert(limit >= tlv_len); assert(limit >= tlv_len);
limit -= tlv_len; limit -= tlv_len;
} }
*offset += tlv_len;
*frame_size += tlv_len; *frame_size += tlv_len;
effective_size += tlv_len; effective_size += tlv_len;
local_esize += tlv_len; local_esize += tlv_len;
} }
print_TL(1, *offset, level, constr, tblen, tlv_tag, tlv_len, print_TL(os, 1, ibs->bytesRead(ibs), level, constr, tblen,
local_esize); tlv_tag, tlv_len, local_esize);
tblen = 0; tblen = 0;
...@@ -386,45 +304,45 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level, ...@@ -386,45 +304,45 @@ process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
} }
static void static void
print_TL(int fin, size_t offset, int level, int constr, ssize_t tlen, print_TL(output_stream_t *os, int fin, off_t offset, int level, int constr,
ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len, ssize_t tlen, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len,
ber_tlv_len_t effective_size) { ber_tlv_len_t effective_size) {
if(fin && !constr) { if(fin && !constr) {
printf("</P>\n"); osprintf(os, "</P>\n");
return; return;
} }
while(level-- > 0) fputs(indent_bytes, stdout); /* Print indent */ while(level-- > 0) osprintf(os, "%s", indent_bytes); /* Print indent */
printf(fin ? "</" : "<"); osprintf(os, fin ? "</" : "<");
printf(constr ? ((tlv_len == -1) ? "I" : "C") : "P"); osprintf(os, constr ? ((tlv_len == -1) ? "I" : "C") : "P");
/* Print out the offset of this boundary, even if closing tag */ /* Print out the offset of this boundary, even if closing tag */
if(!minimalistic) printf(" O=\"%zu\"", offset); if(!minimalistic) osprintf(os, " O=\"%lld\"", offset);
printf(" T=\""); osprintf(os, " T=\"%s\"", ber_tlv_tag_string(tlv_tag));
ber_tlv_tag_fwrite(tlv_tag, stdout);
printf("\"");
if(!fin || (tlv_len == -1 && !minimalistic)) if(!fin || (tlv_len == -1 && !minimalistic))
printf(" TL=\"%ld\"", (long)tlen); osprintf(os, " TL=\"%ld\"", (long)tlen);
if(!fin) { if(!fin) {
if(tlv_len == -1) if(tlv_len == -1)
printf(" V=\"Indefinite\""); osprintf(os, " V=\"Indefinite\"");
else else
printf(" V=\"%ld\"", (long)tlv_len); osprintf(os, " V=\"%ld\"", (long)tlv_len);
} }
if(!minimalistic && BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) { if(!minimalistic && BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
const char *str; const char *str;
ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag); ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
str = ASN_UNIVERSAL_TAG2STR(tvalue); str = ASN_UNIVERSAL_TAG2STR(tvalue);
if(str) printf(" A=\"%s\"", str); if(str) osprintf(os, " A=\"%s\"", str);
} }
if(fin) { if(fin) {
if(constr && !minimalistic) printf(" L=\"%ld\"", (long)effective_size); if(constr && !minimalistic) {
printf(">\n"); osprintf(os, " L=\"%ld\"", (long)effective_size);
}
osprintf(os, ">\n");
} }
} }
...@@ -432,8 +350,8 @@ print_TL(int fin, size_t offset, int level, int constr, ssize_t tlen, ...@@ -432,8 +350,8 @@ print_TL(int fin, size_t offset, int level, int constr, ssize_t tlen,
* Print the value in binary form, or reformat for pretty-printing. * Print the value in binary form, or reformat for pretty-printing.
*/ */
static int static int
print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, print_V(const char *fname, input_stream_t *ibs, output_stream_t *os,
ber_tlv_len_t tlv_len) { ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len) {
asn_oid_arc_t *arcs = 0; /* Object identifier arcs */ asn_oid_arc_t *arcs = 0; /* Object identifier arcs */
unsigned char *vbuf = 0; unsigned char *vbuf = 0;
asn1p_expr_type_e etype = 0; asn1p_expr_type_e etype = 0;
...@@ -505,16 +423,16 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ...@@ -505,16 +423,16 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
} }
/* If collection vbuf is present, defer printing the F flag. */ /* If collection vbuf is present, defer printing the F flag. */
if(!vbuf) printf(special_format ? " F>" : ">"); if(!vbuf) osprintf(os, special_format ? " F>" : ">");
/* /*
* Print the value in binary or text form, * Print the value in binary or text form,
* or collect the bytes into vbuf. * or collect the bytes into vbuf.
*/ */
for(i = 0; i < tlv_len; i++) { for(i = 0; i < tlv_len; i++) {
int ch = fgetc(fp); int ch = ibs_getc(ibs);
if(ch == -1) { if(ch == -1) {
fprintf(stderr, "%s: Unexpected end of file (V)\n", fname); osprintfError(os, "%s: Unexpected end of file (V)\n", fname);
if(vbuf) FREEMEM(vbuf); if(vbuf) FREEMEM(vbuf);
if(arcs) FREEMEM(arcs); if(arcs) FREEMEM(arcs);
return -1; return -1;
...@@ -531,26 +449,26 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ...@@ -531,26 +449,26 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
default: default:
if(((etype == ASN_STRING_UTF8String) || !(ch & 0x80)) if(((etype == ASN_STRING_UTF8String) || !(ch & 0x80))
&& (ch >= 0x20)) { && (ch >= 0x20)) {
printf("%c", ch); osprintf(os, "%c", ch);
break; break;
} }
/* Fall through */ /* Fall through */
case 0x3c: case 0x3c:
case 0x3e: case 0x3e:
case 0x26: case 0x26:
printf("&#x%02x;", ch); osprintf(os, "&#x%02x;", ch);
} }
break; break;
case ASN_BASIC_BOOLEAN: case ASN_BASIC_BOOLEAN:
switch(ch) { switch(ch) {
case 0: case 0:
printf("<false/>"); osprintf(os, "<false/>");
break; break;
case 0xff: case 0xff:
printf("<true/>"); osprintf(os, "<true/>");
break; break;
default: default:
printf("<true value=\"&#x%02x\"/>", ch); osprintf(os, "<true value=\"&#x%02x\"/>", ch);
} }
break; break;
case ASN_BASIC_INTEGER: case ASN_BASIC_INTEGER:
...@@ -564,7 +482,7 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ...@@ -564,7 +482,7 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
if(vbuf) { if(vbuf) {
vbuf[i] = ch; vbuf[i] = ch;
} else { } else {
printf("&#x%02x;", ch); osprintf(os, "&#x%02x;", ch);
} }
} }
} }
...@@ -573,7 +491,7 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ...@@ -573,7 +491,7 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
switch(etype) { switch(etype) {
case ASN_BASIC_INTEGER: case ASN_BASIC_INTEGER:
case ASN_BASIC_ENUMERATED: case ASN_BASIC_ENUMERATED:
printf("%s", asn1p_itoa(collector)); osprintf(os, "%s", asn1p_itoa(collector));
break; break;
case ASN_BASIC_OBJECT_IDENTIFIER: case ASN_BASIC_OBJECT_IDENTIFIER:
if(vbuf) { if(vbuf) {
...@@ -586,10 +504,10 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ...@@ -586,10 +504,10 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs, tlv_len + 1); arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs, tlv_len + 1);
if(arcno >= 0) { if(arcno >= 0) {
assert(arcno <= (tlv_len + 1)); assert(arcno <= (tlv_len + 1));
printf(" F>"); osprintf(os, " F>");
for(i = 0; i < arcno; i++) { for(i = 0; i < arcno; i++) {
if(i) printf("."); if(i) osprintf(os, ".");
printf("%" PRIu32, arcs[i]); osprintf(os, "%" PRIu32, arcs[i]);
} }
FREEMEM(vbuf); FREEMEM(vbuf);
vbuf = 0; vbuf = 0;
...@@ -607,10 +525,10 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ...@@ -607,10 +525,10 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
arcno = RELATIVE_OID_get_arcs(&oid, arcs, tlv_len); arcno = RELATIVE_OID_get_arcs(&oid, arcs, tlv_len);
if(arcno >= 0) { if(arcno >= 0) {
assert(arcno <= tlv_len); assert(arcno <= tlv_len);
printf(" F>"); osprintf(os, " F>");
for(i = 0; i < arcno; i++) { for(i = 0; i < arcno; i++) {
if(i) printf("."); if(i) osprintf(os, ".");
printf("%" PRIu32, arcs[i]); osprintf(os, "%" PRIu32, arcs[i]);
} }
FREEMEM(vbuf); FREEMEM(vbuf);
vbuf = 0; vbuf = 0;
...@@ -650,16 +568,16 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ...@@ -650,16 +568,16 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
} }
break; break;
} }
printf(">"); osprintf(os, ">");
for(i = 0; i < tlv_len; i++) { for(i = 0; i < tlv_len; i++) {
if(binary > 0 || vbuf[i] < 0x20 || vbuf[i] >= 0x7f if(binary > 0 || vbuf[i] < 0x20 || vbuf[i] >= 0x7f
|| vbuf[i] == 0x26 /* '&' */ || vbuf[i] == 0x26 /* '&' */
|| vbuf[i] == 0x3c /* '<' */ || vbuf[i] == 0x3c /* '<' */
|| vbuf[i] == 0x3e /* '>' */ || vbuf[i] == 0x3e /* '>' */
) )
printf("&#x%02x;", vbuf[i]); osprintf(os, "&#x%02x;", vbuf[i]);
else else
printf("%c", vbuf[i]); osprintf(os, "%c", vbuf[i]);
} }
FREEMEM(vbuf); FREEMEM(vbuf);
} }
...@@ -668,9 +586,78 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ...@@ -668,9 +586,78 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
return 0; return 0;
} }
struct file_input_stream {
input_stream_t istream;
FILE *fp;
off_t offset;
};
static int file_input_stream_nextChar(input_stream_t *ibs) {
struct file_input_stream *fs = (struct file_input_stream *)ibs;
int ret = fgetc(fs->fp);
if(ret != -1) {
fs->offset++;
}
return ret;
}
static off_t file_input_stream_bytesRead(input_stream_t *ibs) {
struct file_input_stream *fs = (struct file_input_stream *)ibs;
return fs->offset;
}
struct file_output_stream {
output_stream_t ostream;
FILE *outputFile;
FILE *errorFile;
};
static int
file_output_stream_vprintf(output_stream_t *os, const char *fmt, va_list ap) {
struct file_output_stream *fos = (struct file_output_stream *)os;
return vfprintf(fos->outputFile, fmt, ap);
}
static int static int
decode_tlv_from_string(const char *datastring) { file_output_stream_vprintfError(output_stream_t *os, const char *fmt, va_list ap) {
struct file_output_stream *fos = (struct file_output_stream *)os;
return vfprintf(fos->errorFile, fmt, ap);
}
int
unber_file(const char *fname) {
FILE *fp;
if(strcmp(fname, "-")) {
fp = fopen(fname, "rb");
if(!fp) {
perror(fname);
return -1;
}
} else {
fp = stdin;
}
struct file_input_stream ifs;
ifs.istream.nextChar = file_input_stream_nextChar;
ifs.istream.bytesRead = file_input_stream_bytesRead;
ifs.fp = fp;
struct file_output_stream ofs;
ofs.ostream.vprintf = file_output_stream_vprintf;
ofs.ostream.vprintfError = file_output_stream_vprintfError;
ofs.outputFile = stdout;
ofs.errorFile = stderr;
int ret = unber_stream(fname, &ifs.istream, &ofs.ostream);
if(fp != stdin) fclose(fp);
return ret;
}
int
decode_tlv_from_hex_string(const char *datastring) {
unsigned char *data, *dp; unsigned char *data, *dp;
size_t dsize; /* Data size */ size_t dsize; /* Data size */
ssize_t len; ssize_t len;
......
/*
* Copyright (c) 2004-2019 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/* Set global options. */
void set_minimalistic_output(int v);
void set_single_type_decoding(int v);
void set_pretty_printing(int v);
int set_skip_bytes(long v);
int set_indent_size(int indent_size);
/*
* Convert BER-encoded file into the low level non-standard XML-like structure.
* Primarily used for manual debugging.
*/
int unber_file(const char *fname);
typedef struct input_stream {
/*
* Return the next character as if it were an unsigned int converted to
* an int. Returns -1 on EOF or error.
*/
int (*nextChar)(struct input_stream *);
/*
* Return the number of bytes consumed from the stream so far.
*/
off_t (*bytesRead)(struct input_stream *);
} input_stream_t;
typedef struct output_stream {
/*
* Return the next character as if it were an unsigned int converted to
* an int. Returns -1 on EOF or error.
*/
int (*vprintf)(struct output_stream *, const char *fmt, va_list);
int (*vprintfError)(struct output_stream *, const char *fmt, va_list);
} output_stream_t;
/*
* Lower level converter.
*/
int unber_stream(const char *fname, input_stream_t *, output_stream_t *);
/*
* Decode the TLV given by the given string.
*/
int decode_tlv_from_hex_string(const char *datastring);
/*
* Copyright (c) 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include "asn1_common.h"
#include "libasn1_unber_tool.h"
#undef COPYRIGHT
#define COPYRIGHT "Copyright (c) 2004-2019 Lev Walkin <vlm@lionet.info>\n"
static void usage(const char *av0); /* Print the Usage screen and exit */
int
main(int ac, char **av) {
int ch; /* Command line character */
/*
* Process command-line options.
*/
while((ch = getopt(ac, av, "1hi:mps:t:v")) != -1) {
switch(ch) {
case '1':
set_single_type_decoding(1);
break;
case 'i':
if(set_indent_size(atoi(optarg)) != 0) {
fprintf(stderr, "-i %s: Invalid indent value\n", optarg);
exit(EX_USAGE);
}
break;
case 'm':
set_minimalistic_output(1);
break;
case 'p':
set_pretty_printing(0);
break;
case 's':
if(set_skip_bytes(atol(optarg)) != 0) {
fprintf(stderr, "-s %s: positive value expected\n", optarg);
exit(EX_USAGE);
}
break;
case 't':
if(decode_tlv_from_hex_string(optarg)) exit(EX_DATAERR);
exit(0);
case 'v':
fprintf(stderr, "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT);
exit(0);
break;
case 'h':
default:
usage(av[0]);
}
}
/*
* Ensure that there are some input files present.
*/
if(ac > optind) {
ac -= optind;
av += optind;
} else {
fprintf(stderr, "%s: No input files specified\n", av[0]);
exit(1);
}
setvbuf(stdout, 0, _IOLBF, 0);
/*
* Iterate over input files and parse each.
* All syntax trees from all files will be bundled together.
*/
for(int i = 0; i < ac; i++) {
if(unber_file(av[i])) exit(EX_DATAERR);
}
return 0;
}
/*
* Print the usage screen and exit(EX_USAGE).
*/
static void
usage(const char *av0) {
/* clang-format off */
fprintf(stderr,
"ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT
"Usage: %s [options] [-] [file ...]\n"
"Options:\n"
" -1 Decode only the first BER structure (otherwise, until EOF)\n"
" -i <indent> Amount of spaces for output indentation (default is 4)\n"
" -m Minimalistic mode: print as little as possible\n"
" -p Do not attempt pretty-printing of known ASN.1 types\n"
" -s <skip> Ignore first <skip> bytes of input\n"
" -t <hex-string> Decode the given tag[/length] sequence (e.g. -t \"bf20\")\n"
"\n"
"The XML opening tag format is as follows:\n"
" <tform O=\"off\" T=\"tag\" TL=\"tl_len\" V=\"{Indefinite|v_len}\" [A=\"type\"] [F]>\n"
"Where:\n"
" tform Which form the value is in: constructed (\"C\", \"I\") or primitive (\"P\")\n"
" off Offset of the encoded element in the unber input stream\n"
" tag The tag class and value in human readable form\n"
" tl_len The length of the TL (BER Tag and Length) encoding\n"
" v_len The length of the value (V, encoded by the L), may be \"Indefinite\"\n"
" type Likely name of the underlying ASN.1 type (for [UNIVERSAL n] tags)\n"
" [F] Indicates that the value was reformatted (pretty-printed)\n"
"See the manual page for details\n"
, av0);
/* clang-format on */
exit(EX_USAGE);
}
...@@ -17,14 +17,4 @@ asn1c_LDADD = \ ...@@ -17,14 +17,4 @@ asn1c_LDADD = \
$(top_builddir)/libasn1fix/libasn1fix.la \ $(top_builddir)/libasn1fix/libasn1fix.la \
$(top_builddir)/libasn1compiler/libasn1compiler.la $(top_builddir)/libasn1compiler/libasn1compiler.la
unber_LDADD = \ bin_PROGRAMS = asn1c
$(top_builddir)/libasn1common/libasn1common.la
bin_PROGRAMS = asn1c unber enber
noinst_HEADERS = sys-common.h
dist_check_SCRIPTS = check-xxber.sh
TESTS_ENVIRONMENT= top_srcdir=${top_srcdir}
TESTS = $(dist_check_SCRIPTS)
CLEANFILES = .check-xxber.*.tmp
asn1c - The ASN.1 Compiler asn1c - The ASN.1 Compiler
unber - The ASN.1 BER Decoder
enber - Reverse unber(1) output back into BER
...@@ -23,13 +23,12 @@ ...@@ -23,13 +23,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id$
*/ */
/* /*
* This is the program that connects the libasn1* libraries together. * This is the program that connects the libasn1* libraries together.
* It uses them in turn to parse, fix and then compile or print the ASN.1 tree. * It uses them in turn to parse, fix and then compile or print the ASN.1 tree.
*/ */
#include "sys-common.h" #include "asn1_common.h"
#undef COPYRIGHT #undef COPYRIGHT
#define COPYRIGHT "Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info> and contributors.\n" #define COPYRIGHT "Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info> and contributors.\n"
......
...@@ -292,6 +292,9 @@ tests/tests-asn1c-smoke/Makefile \ ...@@ -292,6 +292,9 @@ tests/tests-asn1c-smoke/Makefile \
tests/tests-randomized/Makefile \ tests/tests-randomized/Makefile \
tests/tests-c-compiler/Makefile \ tests/tests-c-compiler/Makefile \
tests/tests-skeletons/Makefile \ tests/tests-skeletons/Makefile \
asn1-tools/enber/Makefile \
asn1-tools/unber/Makefile \
asn1-tools/Makefile \
libasn1compiler/Makefile \ libasn1compiler/Makefile \
libasn1common/Makefile \ libasn1common/Makefile \
libasn1parser/Makefile \ libasn1parser/Makefile \
......
...@@ -5,7 +5,7 @@ AM_CFLAGS = @ADD_CFLAGS@ ...@@ -5,7 +5,7 @@ AM_CFLAGS = @ADD_CFLAGS@
noinst_LTLIBRARIES = libasn1common.la noinst_LTLIBRARIES = libasn1common.la
libasn1common_la_SOURCES = \ libasn1common_la_SOURCES = \
asn1_ref.c asn1_ref.h \ asn1_common.h asn1_ref.c asn1_ref.h \
asn1_buffer.c asn1_buffer.h \ asn1_buffer.c asn1_buffer.h \
asn1_namespace.c asn1_namespace.h \ asn1_namespace.c asn1_namespace.h \
genhash.c genhash.h genhash.c genhash.h
......
...@@ -4,15 +4,17 @@ ...@@ -4,15 +4,17 @@
diff -a . . 2>/dev/null && diffArgs="-a" # Assume text files diff -a . . 2>/dev/null && diffArgs="-a" # Assume text files
diff -u . . 2>/dev/null && diffArgs="$diffArgs -u" # Unified diff output diff -u . . 2>/dev/null && diffArgs="$diffArgs -u" # Unified diff output
ec=0 finalExitCode=0
if [ "$1" != "regenerate" ]; then if [ "$1" != "regenerate" ]; then
set -e set -e
fi fi
PROCESSING="" LAST_FAILED=""
print_status() { print_status() {
echo "Error while processing $PROCESSING" if [ -n "${LAST_FAILED}" ]; then
echo "Error while processing $LAST_FAILED"
fi
} }
trap print_status EXIT trap print_status EXIT
...@@ -29,20 +31,20 @@ for ref in ${top_srcdir}/tests/tests-asn1c-compiler/*.asn1.-*; do ...@@ -29,20 +31,20 @@ for ref in ${top_srcdir}/tests/tests-asn1c-compiler/*.asn1.-*; do
template=.tmp.check-parsing.$$ template=.tmp.check-parsing.$$
oldversion=${template}.old oldversion=${template}.old
newversion=${template}.new newversion=${template}.new
PROCESSING="$ref (from $src)"
LANG=C sed -e 's/^found in .*/found in .../' < "$ref" > "$oldversion" LANG=C sed -e 's/^found in .*/found in .../' < "$ref" > "$oldversion"
ec=0
(${top_builddir}/asn1c/asn1c -S ${top_srcdir}/skeletons -no-gen-OER -no-gen-PER "-$flags" "$src" | LANG=C sed -e 's/^found in .*/found in .../' > "$newversion") || ec=$? (${top_builddir}/asn1c/asn1c -S ${top_srcdir}/skeletons -no-gen-OER -no-gen-PER "-$flags" "$src" | LANG=C sed -e 's/^found in .*/found in .../' > "$newversion") || ec=$?
if [ $? = 0 ]; then if [ $? = 0 ]; then
diff $diffArgs "$oldversion" "$newversion" || ec=$? diff $diffArgs "$oldversion" "$newversion" || ec=$?
fi fi
if [ $ec != 0 ]; then
LAST_FAILED="$ref (from $src)"
finalExitCode=$ec
fi
rm -f $oldversion $newversion rm -f $oldversion $newversion
if [ "$1" = "regenerate" ]; then if [ "$1" = "regenerate" ]; then
${top_builddir}/asn1c/asn1c -S ${top_srcdir}/skeletons -no-gen-OER -no-gen-PER "-$flags" "$src" > "$ref" ${top_builddir}/asn1c/asn1c -S ${top_srcdir}/skeletons -no-gen-OER -no-gen-PER "-$flags" "$src" > "$ref"
fi fi
done done
if [ $ec = 0 ]; then exit $finalExitCode
trap '' EXIT
fi
exit $ec
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment