1 /**
2     Abstract Syntax Notation 1 is a high-level syntax specification created
3     by the $(LINK https://www.itu.int/en/pages/default.aspx,
4     International Telecommunications Union) in
5     $(LINK https://www.itu.int/rec/T-REC-X.680/en,
6     X.680 - Abstract Syntax Notation One (ASN.1)), that
7     abstractly defines data structures and protocol data units used by
8     programs and protocols. It defines an extensible system of data types,
9     modules, and data structures.
10 
11     While described abstractly by ASN.1, the specified protocol data units
12     and data structures can be encoded via various encoding schemes, such as
13     the Basic Encoding Rules (BER), which are defined in the
14     $(LINK https://www.itu.int/en/pages/default.aspx,
15     International Telecommunications Union)'s
16     $(LINK http://www.itu.int/rec/T-REC-X.690/en, X.690 - ASN.1 encoding rules).
17     These encoding schemes uniformly relay data between systems that
18     can differ in endianness, bit-width, byte-size, operating system,
19     machine architecture, and so on.
20 
21     The encoding schemata that inherit from ASN.1 are used widely in protocols
22     such as TLS, LDAP, SNMP, RDP, and many more.
23 
24     Author:
25         $(LINK http://jonathan.wilbur.space, Jonathan M. Wilbur)
26             $(LINK mailto:jonathan@wilbur.space, jonathan@wilbur.space)
27     License: $(LINK https://mit-license.org/, MIT License)
28     Standards:
29         $(LINK https://www.itu.int/rec/T-REC-X.680/en, X.680 - Abstract Syntax Notation One (ASN.1))
30     See_Also:
31         $(LINK https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One, The Wikipedia Page on ASN.1)
32         $(LINK https://www.strozhevsky.com/free_docs/asn1_in_simple_words.pdf, ASN.1 By Simple Words)
33         $(LINK http://www.oss.com/asn1/resources/books-whitepapers-pubs/dubuisson-asn1-book.PDF, ASN.1: Communication Between Heterogeneous Systems)
34 */
35 module asn1;
36 
37 /*
38     Done to avoid the problems associated with CVE-2009-0789. I don't know this
39     to be a bug with this code, but it is better to play on the safe side.
40     Remove at your own peril.
41 */
42 static assert(!(long.sizeof < (void *).sizeof));
43 
44 debug (asn1)
45 {
46     public import std.stdio : write, writefln, writeln;
47 }
48 
49 version (unittest)
50 {
51     public import core.exception : AssertError, RangeError;
52     public import std.exception : assertNotThrown, assertThrown;
53     public import std.math : approxEqual;
54     public import std.stdio : write, writefln, writeln;
55 }
56 
57 // Check fundamental assumptions of this library.
58 static assert(char.sizeof == 1u);
59 static assert(wchar.sizeof == 2u);
60 static assert(dchar.sizeof == 4u);
61 static assert(double.sizeof > float.sizeof);
62 static assert(real.sizeof >= double.sizeof);
63 
64 ///
65 public alias ASN1Exception = AbstractSyntaxNotation1Exception;
66 /// A Generic Exception from which all other ASN.1 Exceptions will inherit.
67 class AbstractSyntaxNotation1Exception : Exception
68 {
69     private import std.exception : basicExceptionCtors;
70     mixin basicExceptionCtors;
71 }
72 
73 ///
74 public alias ASN1TagClass = AbstractSyntaxNotation1TagClass;
75 ///
76 immutable public
77 enum AbstractSyntaxNotation1TagClass : ubyte
78 {
79     universal = 0b00000000u, // Native to ASN.1
80     application = 0b01000000u, // Only valid for one specific application
81     contextSpecific = 0b10000000u, // Specific to a sequence, set, or choice
82     privatelyDefined = 0b11000000u// Defined in private specifications
83 }
84 
85 ///
86 public alias ASN1Construction = AbstractSyntaxNotation1Construction;
87 ///
88 immutable public
89 enum AbstractSyntaxNotation1Construction : ubyte
90 {
91     primitive = 0b00000000u, // The content octets directly encode the element value
92     constructed = 0b00100000u // The content octets contain 0, 1, or more element encodings
93 }
94 
95 ///
96 public alias ASN1UniversalType = AbstractSyntaxNotation1UniversalType;
97 /**
98     The data types, as well as their permitted construction and numeric
99     identifiers, according to the
100     $(LINK https://www.itu.int/en/pages/default.aspx,
101     International Telecommunications Union)'s
102     $(LINK http://www.itu.int/rec/T-REC-X.690/en, X.690 - ASN.1 encoding rules)
103 
104     $(TABLE
105         $(TR $(TH Type)                 $(TH Construction)      $(TH Hexadecimal Value))
106         $(TR $(TD End-of-Content)       $(TD Primitive)         $(TD 0x00))
107         $(TR $(TD BOOLEAN)	            $(TD Primitive)         $(TD 0x01))
108         $(TR $(TD INTEGER)	            $(TD Primitive)         $(TD 0x02))
109         $(TR $(TD BIT STRING)           $(TD Both)              $(TD 0x03))
110         $(TR $(TD OCTET STRING)         $(TD Both)              $(TD 0x04))
111         $(TR $(TD NULL)                 $(TD Primitive)         $(TD 0x05))
112         $(TR $(TD OBJECT IDENTIFIER)	$(TD Primitive)         $(TD 0x06))
113         $(TR $(TD Object Descriptor)    $(TD Both)              $(TD 0x07))
114         $(TR $(TD EXTERNAL)	            $(TD Constructed)       $(TD 0x08))
115         $(TR $(TD REAL)            	    $(TD Primitive)         $(TD 0x09))
116         $(TR $(TD ENUMERATED)	        $(TD Primitive)         $(TD 0x0A))
117         $(TR $(TD EmbeddedPDV)	        $(TD Constructed)       $(TD 0x0B))
118         $(TR $(TD UTF8String)	        $(TD Both)              $(TD 0x0C))
119         $(TR $(TD RELATIVE-OID)	        $(TD Primitive)         $(TD 0x0D))
120         $(TR $(TD SEQUENCE)	            $(TD Constructed)       $(TD 0x10))
121         $(TR $(TD SET)	                $(TD Constructed)       $(TD 0x11))
122         $(TR $(TD NumericString)	    $(TD Both)              $(TD 0x12))
123         $(TR $(TD PrintableString)	    $(TD Both)              $(TD 0x13))
124         $(TR $(TD T61String)	        $(TD Both)              $(TD 0x14))
125         $(TR $(TD VideotexString)	    $(TD Both)              $(TD 0x15))
126         $(TR $(TD IA5String)	        $(TD Both)              $(TD 0x16))
127         $(TR $(TD UTCTime)	            $(TD Both)              $(TD 0x17))
128         $(TR $(TD GeneralizedTime)	    $(TD Both)              $(TD 0x18))
129         $(TR $(TD GraphicString)	    $(TD Both)              $(TD 0x19))
130         $(TR $(TD VisibleString)	    $(TD Both)              $(TD 0x1A))
131         $(TR $(TD GeneralString)	    $(TD Both)              $(TD 0x1B))
132         $(TR $(TD UniversalString)	    $(TD Both)              $(TD 0x1C))
133         $(TR $(TD CHARACTER STRING)	    $(TD Both)              $(TD 0x1D))
134         $(TR $(TD BMPString)	        $(TD Both)              $(TD 0x1E))
135     )
136 */
137 immutable public
138 enum AbstractSyntaxNotation1UniversalType : ubyte
139 {
140     endOfContent = 0x00u,
141     eoc = endOfContent,
142     boolean = 0x01u,
143     integer = 0x02u,
144     bitString = 0x03u,
145     octetString = 0x04u,
146     nill = 0x05u,
147     objectIdentifier = 0x06u,
148     oid = objectIdentifier,
149     objectDescriptor = 0x07u,
150     external = 0x08u,
151     ext = external,
152     realNumber = 0x09u,
153     enumerated = 0x0Au,
154     embeddedPresentationDataValue = 0x0Bu,
155     embeddedPDV = embeddedPresentationDataValue,
156     pdv = embeddedPresentationDataValue,
157     unicodeTransformationFormat8String = 0x0Cu,
158     utf8String = unicodeTransformationFormat8String,
159     utf8 = unicodeTransformationFormat8String,
160     relativeObjectIdentifier = 0x0Du,
161     relativeOID = relativeObjectIdentifier,
162     roid = relativeObjectIdentifier,
163     reserved14 = 0x0Eu,
164     reserved15 = 0x0Fu,
165     sequence = 0x10u,
166     set = 0x11u,
167     numericString = 0x12u,
168     numeric = numericString,
169     printableString = 0x13u,
170     printable = printableString,
171     teletexString = 0x14u,
172     t61String = teletexString,
173     videotexString = 0x15u,
174     internationalAlphabetNumber5String = 0x16u,
175     ia5String = internationalAlphabetNumber5String,
176     coordinatedUniversalTime = 0x17u,
177     utcTime = coordinatedUniversalTime,
178     generalizedTime = 0x18u,
179     graphicString = 0x19u,
180     graphic = graphicString,
181     visibleString = 0x1Au,
182     visible = visibleString,
183     generalString = 0x1Bu,
184     general = generalString,
185     universalString = 0x1Cu,
186     universal = universalString,
187     characterString = 0x1Du,
188     basicMultilingualPlaneString = 0x1Eu,
189     bmpString = basicMultilingualPlaneString
190 }
191 
192 ///
193 public alias ASN1LengthEncoding = AbstractSyntaxNotation1LengthEncoding;
194 ///
195 public
196 enum AbstractSyntaxNotation1LengthEncoding : ubyte
197 {
198     definiteShort = 0b00000000u, // Least significant seven bits of length octet encode content length of 0 - 127 bytes
199     indefinite = 0b10000000u, // Content ends when two endOfContent bytes are encountered.
200     definiteLong = 0b10000001u, // Least significant seven bits of length octet encode how many more length octets
201     reserved = 0b11111111u
202 }
203 
204 ///
205 public alias ASN1RealEncodingBase = AbstractSyntaxNotation1RealEncodingBase;
206 ///
207 immutable public
208 enum AbstractSyntaxNotation1RealEncodingBase : ubyte
209 {
210     base2 = 0x02u,
211     base8 = 0x08u,
212     base10 = 0x0Au,
213     base16 = 0x10u
214 }
215 
216 ///
217 public alias ASN1RealEncodingScale = AbstractSyntaxNotation1RealEncodingScale;
218 ///
219 immutable public
220 enum AbstractSyntaxNotation1RealEncodingScale : ubyte
221 {
222     scale0 = 0x00u,
223     scale1 = 0x01u,
224     scale2 = 0x02u,
225     scale3 = 0x03u
226 }
227 
228 ///
229 public alias ASN1RealExponentEncoding = AbstractSyntaxNotation1RealExponentEncoding;
230 ///
231 immutable public
232 enum AbstractSyntaxNotation1RealExponentEncoding : ubyte
233 {
234     followingOctet = 0b00000000u,
235     following2Octets = 0b00000001u,
236     following3Octets = 0b00000010u,
237     complicated = 0b00000011u // Just calling it as I see it.
238 }
239 
240 ///
241 public alias ASN1SpecialRealValue = AbstractSyntaxNotation1SpecialRealValue;
242 /**
243     Special values for REALs, as assigned in section 8.5.9 of X.690.
244 
245     Note that NOT-A-NUMBER and minus zero were added in the 2015 version.
246 */
247 immutable public
248 enum AbstractSyntaxNotation1SpecialRealValue : ubyte
249 {
250     plusInfinity = 0b01000000u,
251     minusInfinity = 0b01000001u,
252     notANumber = 0b01000010u,
253     minusZero = 0b01000011u
254 }
255 
256 ///
257 public alias ASN1Base10RealNumericalRepresentation = AbstractSyntaxNotation1Base10RealNumericalRepresentation;
258 /**
259     The standardized string representations of floating point numbers, as
260     specified in $(LINK https://www.iso.org/standard/12285.html, ISO 6093).
261 
262     $(TABLE
263         $(TR $(TH Representation) $(TH Description) $(TH Examples))
264         $(TR $(TD NR1) $(TD Implicit decimal point) $(TD "3", "-1", "+1000"))
265         $(TR $(TD NR2) $(TD Explicit decimal) $(TD "3.0", "-1.3", "-.3"))
266         $(TR $(TD NR3) $(TD Explicit exponent) $(TD "3.0E1", "123E+100"))
267     )
268 
269     Citations:
270         Dubuisson, Olivier. “Character String Types.” ASN.1:
271             Communication between Heterogeneous Systems, Morgan
272             Kaufmann, 2001, p. 143.
273 */
274 immutable public
275 enum AbstractSyntaxNotation1Base10RealNumericalRepresentation : ubyte
276 {
277     nr1 = 0b00000001u,
278     nr2 = 0b00000010u,
279     nr3 = 0b00000011
280 }
281 
282 /// The acceptable characters for a NumericString
283 immutable public string numericStringCharacters = "0123456789 ";
284 
285 /**
286     The acceptable characters for a printableString.
287 
288     The sorting of letters below is a slight optimization:
289     they are sorted in order of decreasing frequency in the English
290     language, so that canFind will usually have to iterate through
291     fewer letters before finding a match.
292 */
293 immutable public string printableStringCharacters =
294     "etaoinsrhdlucmfywgpbvkxqjzETAOINSRHDLUCMFYWGPBVKXQJZ0123456789 '()+,-./:=?";