1 /**
2 * ASN.1 Internals
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 
12 module botan.asn1.asn1_obj;
13 
14 import botan.constants;
15 public import botan.asn1.der_enc;
16 public import botan.asn1.ber_dec;
17 public import botan.asn1.alg_id;
18 public import botan.filters.data_src;
19 import botan.utils.parsing;
20 import botan.utils.exceptn;
21 import memutils.vector : SecureVector;
22 import std.conv : to;
23 import botan.utils.types;
24 
25 /**
26 * ASN.1 Type and Class Tags
27 */
28 enum ASN1Tag {
29     UNIVERSAL            = 0x00,
30     APPLICATION          = 0x40,
31     CONTEXT_SPECIFIC     = 0x80,
32     
33     CONSTRUCTED          = 0x20,
34 
35     PRIVATE              = ASN1Tag.CONSTRUCTED | ASN1Tag.CONTEXT_SPECIFIC,
36 
37     EOC                  = 0x00,
38     BOOLEAN              = 0x01,
39     INTEGER              = 0x02,
40     BIT_STRING           = 0x03,
41     OCTET_STRING         = 0x04,
42     NULL_TAG             = 0x05,
43     OBJECT_ID            = 0x06,
44     ENUMERATED           = 0x0A,
45     SEQUENCE             = 0x10,
46     SET                  = 0x11,
47 
48     UTF8_STRING          = 0x0C,
49     NUMERIC_STRING       = 0x12,
50     PRINTABLE_STRING     = 0x13,
51     T61_STRING           = 0x14,
52     IA5_STRING           = 0x16,
53     VISIBLE_STRING       = 0x1A,
54     BMP_STRING           = 0x1E,
55 
56     UTC_TIME             = 0x17,
57     GENERALIZED_TIME     = 0x18,
58 
59     NO_OBJECT            = 0xFF00,
60     DIRECTORY_STRING     = 0xFF01
61 }
62 
63 /**
64 * Basic ASN.1 Object Interface
65 */
66 interface ASN1Object
67 {
68 
69 public:
70     /**
71     * Encode whatever this object is into to
72     * Params:
73     *  to = the $(D DEREncoder) that will be written to
74     */
75     void encodeInto(ref DEREncoder to) const;
76 
77     /**
78     * Decode whatever this object is from from
79     * 
80     * Params:
81     *  from = the BERDecoder that will be read from
82     */
83     void decodeFrom(ref BERDecoder from);
84 }
85 
86 /**
87 * BER Encoded Object
88 */
89 struct BERObject
90 {
91 public:
92     /**
93     * Check a type invariant on BER data
94     */
95     void assertIsA(ASN1Tag type_tag, ASN1Tag class_tag)
96     {
97         if (this.type_tag != type_tag || this.class_tag != class_tag) {
98             throw new BERDecodingError("Tag mismatch when decoding got " ~
99                                          to!string(this.type_tag) ~ "/" ~
100                                          to!string(this.class_tag) ~ " expected " ~
101                                          to!string(type_tag) ~ "/" ~
102                                          to!string(class_tag));
103         }
104         return;
105     }
106 
107     /**
108     * Convert a BER object into a string object
109     */
110     string toString()
111     {
112         return cast(string) value[].idup;
113     }
114 
115     void swap(ref BERObject other) {
116         import std.algorithm : swap;
117         swap(type_tag, other.type_tag);
118         swap(class_tag, other.class_tag);
119         value.swap(other.value);
120     }
121 
122     BERObject move() {
123         return BERObject(type_tag, class_tag, value.move());
124     }
125 
126     BERObject dup() {
127         return BERObject(type_tag, class_tag, value.dup());
128     }
129 
130     ASN1Tag type_tag, class_tag;
131     SecureVector!ubyte value;
132 }
133 
134 /**
135 * General BER Decoding Error Exception
136 */
137 class BERDecodingError : DecodingError
138 {
139     this(in string str) {
140         super("BER: " ~ str);
141     }
142 }
143 
144 /**
145 * Exception For Incorrect BER Taggings
146 */
147 class BERBadTag : BERDecodingError
148 {
149 
150     /*
151     * BER Decoding Exceptions
152     */
153     this(in string str, ASN1Tag tag) {
154         super(str ~ ": " ~ to!string(tag));
155     }
156 
157     /*
158     * BER Decoding Exceptions
159     */
160     this(in string str, ASN1Tag tag1, ASN1Tag tag2) {
161         super(str ~ ": " ~ to!string(tag1) ~ "/" ~ to!string(tag2));
162     }
163 }
164     
165 /**
166 * Put some arbitrary bytes into a ASN1Tag.SEQUENCE
167 */
168 Vector!ubyte putInSequence(ALLOC)(auto const ref Vector!(ubyte, ALLOC) contents)
169 {
170     return DEREncoder()
171             .startCons(ASN1Tag.SEQUENCE)
172             .rawBytes(contents)
173             .endCons()
174             .getContentsUnlocked();
175 }
176 
177 /// ditto
178 Vector!ubyte putInSequence(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) contents)
179 {
180     return DEREncoder()
181             .startCons(ASN1Tag.SEQUENCE)
182             .rawBytes(contents)
183             .endCons()
184             .getContentsUnlocked();
185 }
186 
187 /**
188 * Heuristics tests; is this object possibly BER?
189 * Params:
190 *  source = a data source that will be peeked at but not modified
191 */
192 bool maybeBER(DataSource source)
193 {
194     ubyte first_byte;
195     if (!source.peekByte(first_byte))
196         throw new StreamIOError("maybeBER: Source was empty");
197     
198     if (first_byte == (ASN1Tag.SEQUENCE | ASN1Tag.CONSTRUCTED))
199         return true;
200     return false;
201 }