Home

Awesome

DDer / MDer

Overview

This repository contains a generic ASN.1/DER parsing library, written in C#, that has the following features:

DDer.exe is a simple command-line tool that converts encoded ASN.1 object (DER or BER) to the structured text-based syntax that is reminiscent of Lisp (i.e. it uses parentheses). MDer.exe performs the reverse operation. These tools are meant to allow easy analysis of DER-encoded objects (in particular X.509 certificates) and creation of synthetic objects from a text editor or a scripting environment. MDer.exe can additionally use parameters to insert sub-objects and elements at various places. The internal classes DDer and MDer provide programmatic access to these fonctionalities, in particular with powerful parametrization features to allow easier building and parsing of objects as used in some complicated ASN.1-based protocols (e.g. exploring X.509 certificate contents).

ZInt is a self-contained big integer implementation, in pure C#. It is implemented in the ZInt.cs file. This file defines the ZInt struct type, which can be used basically like plain integers thanks to operator overloads. It offers functionalities similar to that of System.Numerics.BigInteger, with the following differences:

ZInt is useful for some mathematics-related tasks, e.g. involving some kinds of cryptography, with the following important caveat: it is not constant-time, and thus MUST NOT be used to manipulate private data. ZInt is meant to support research tasks and prototyping.

License

License is MIT-like: you acknowledge that the code is provided without any guarantee of anything, and that I am not liable for anything which follows from using it. Subject to these conditions, you can do whatever you want with the code. See the LICENSE file in the source code for the legal wording.

Installation

The source code is obtained from GitHub; use the "Download ZIP" to obtain a fresh snapshot, or use git to clone the repository. In the source tree, you will find the simple build scripts, build.cmd (for Windows) and build.sh (for Linux and OS X).

The Windows script invokes the command-line compiler (csc.exe) that is found in the v2.0.50727 .NET framework. This framework is installed by default on Windows 7. More recent versions of Windows do not have the .NET 2.0 framework, but a more recent version (4.x or later). Though these framework versions are not completely compatible with each other, TestSSLServer uses only features that work identically on both, so you can compile TestSSLServer with either .NET version. The resulting TestSSLServer.exe is stand-alone and needs no further "installation"; you simply copy the file where you want it to be, and run it from a console (cmd.exe) with the appropriate arguments.

The Linux / OS X script tries to invoke the Mono C# compiler under the names mono-csc (which works on Ubuntu) and dmcs (which works on OS X). On Ubuntu, install the mono-devel package; it should pull as dependencies the runtime and the compiler. On OS X, fetch a package from the Mono project and install it; it should provide the mono command-line tool to run compiled asemblies, and dmcs to invoke the C# compiler.

Usage

On Windows, the compiled DDer.exe and MDer.exe files can be launched directly. On Linux and OS X, use mono DDer.exe and mono MDer.exe.

DDer.exe expects one or several file names; in each file, a single ASN.1 object will be decoded. Files may contain the raw object (in binary), a Base64-encoded object, or a PEM object (Base64-encoding with the -----BEGIN XXX----- and -----END XXX----- headers). Object type is automatically detected. Decoded format is written on standard output, so use a shell redirection to store it in a file. If no file name is provided, then standard input is used.

A file name given as "-" (a single minus character) designates standard input. Since DDer.exe reads each input source as a whole, the "-" source can be given only once on the command-line.

The -n command-line option forces DDer.exe to produce numerical output for all OIDs. Without that option, DDer.exe will recognize some standard OIDs and provide their name (e.g. if the OID is 2.5.29.15, DDer will print its symbolic name id-ce-keyUsage).

The -i pref command-line option makes DDer.exe use the string provided as the pref parameter for each indentation level; normally, pref will consist of one or several spaces. Default indentation prefix is four spaces. If pref is set to none, then no indentation is used, and newlines are suppressed (the output will fit on a single line of text).

MDer.exe expects two arguments: first one is the name of the source file (text encoding of the value), second one is the name of the output file to produce. Output is always binary DER (no Base64). If the name of the input file is "-" (a single minus character), then the source text is read from standard input. Similarly, if the output file name is "-", then the encoded DER object will be written on standard output (as binary).

Extra arguments to MDer.exe are extra values that can be inserted in the output object by using parameter references such as %0, %1... See the MDer class for details. The command-line tool can only use string parameters; the MDer class gives programmatic access to parameterized object building which can use constructed objects.

Syntax

We describe here the base text syntax, as is produced by DDer.exe and expected by MDer.exe. This does not cover use of parameters for programmatic building or parsing; see the MDer class for details.

Text format consists in tokens, with the following rules:

An ASN.1 object has the following generic format:

( [ class tag ] name value )

with the following rules:

The following object types are defined:

Notes

Sub-Objects for Blobs

When decoding a BIT STRING or OCTET STRING, DDer will check if the value is itself a valid DER-encoded object. If it is, then the "sub-object" syntax is used; otherwise, hexadecimal bytes are used. It can thus happen that a binary value turns out to be interpreted as a sub-object; e.g., if a 20-byte key identifier in a certificate (nominally a hash output) starts with bytes 0x04 0x12, then it will "look like" a DER-encoded OCTET STRING and will be decoded as such. In practice, this occurs very rarely.

DDer takes care not to use a sub-object if MDer would not reencode the value exactly. Such things may happen because many encoding variants are accepted (e.g. endianness in character strings, minimality of integer values, BER indefinite lengths...) but not transcribed in the text output of DDer. If the output would not be reencoded exactly, then hexadecimal output is produced instead of a sub-object.

Checks on Strings

DDer and MDer check that string contents match their respective types. Therefore, if you want to produce (for testing reasons) an "invalid" string, you should use another type with a tag override. For instance, this:

([universal 19] ia5 "foo&bar")

produces a value with the tag for PrintableString (universal 19), but the contents include a "&" character which is not allowed in a PrintableString. When decoding it back, DDer will complain ("unexpected character U+0026 in string of type 19").

Tentative String Decoding

If an OCTET STRING or a BIT STRING contains bytes that appear to be "plain ASCII" (all byte values are 9, 10, 13, or between 32 and 126, inclusive), then DDer assumes that the bytes may be an encoded ASCII string, and prints out the string contents as a string literal enclosed in a brace-delimited comment. This is done in addition to the normal hexadecimal printout for such values.

This is used for instance with GeneralName structures, which are commonly encountered in certificates for encoding URL (the format for such an URL is an IA5String with a contextual tag override of value 6, so the fact that it is an IA5String is not known to DDer).

GeneralString and TeletexString

The ASN.1 GeneralString and TeletexString types are handled as ISO-8859-1, aka "Latin-1", i.e. as sequences of characters with a one-byte-per-character mapping. This does not conform to the de jure ASN.1 standard, but aligns with common practice in protocols that use such types. In any case, this allows reading and writing arbitrary string contents through \x escape sequences in string literals.

Date and Time Processing

When decoding a time string (UTCTime or GeneralizedTime), DDer produces both the string contents as a string literal, and a human readable date and time in a brace-delimited comment. Note that a DateTime object is used internally, with the following consequences:

All this only matters for the human-readable printout, which is a comment. The string literal still contains the complete string, as it was received.

Memory Allocation Behaviour

When decoding, the underlying ASN.1 library copies the whole input buffer exactly once, then keeps references within that buffer. This should make it immune to, or at least robust against, malformed inputs with extra-large announced lengths in headers: if a 20-byte object begins with a header that claims the value length to be one gigabyte, DDer will not allocate a one-gigabyte array.

Accepted Variants

DDer accepts as input a number of variants which are not strict DER, but are still unambiguous. These variants include the following:

Numerical Limits

DDer and MDer operate under the following constraints:

Values which exceed these limits are detected and trigger exceptions.

Author

Question and comments can be sent to: Thomas Pornin <pornin@bolet.org>