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 clone() {
127         return BERObject(type_tag, class_tag, value.clone());
128     }
129 
130     @disable @property BERObject dup();
131 
132     ASN1Tag type_tag, class_tag;
133     SecureVector!ubyte value;
134 }
135 
136 /**
137 * General BER Decoding Error Exception
138 */
139 class BERDecodingError : DecodingError
140 {
141     this(in string str) {
142         super("BER: " ~ str);
143     }
144 }
145 
146 /**
147 * Exception For Incorrect BER Taggings
148 */
149 class BERBadTag : BERDecodingError
150 {
151 
152     /*
153     * BER Decoding Exceptions
154     */
155     this(in string str, ASN1Tag tag) {
156         super(str ~ ": " ~ to!string(tag));
157     }
158 
159     /*
160     * BER Decoding Exceptions
161     */
162     this(in string str, ASN1Tag tag1, ASN1Tag tag2) {
163         super(str ~ ": " ~ to!string(tag1) ~ "/" ~ to!string(tag2));
164     }
165 }
166     
167 /**
168 * Put some arbitrary bytes into a ASN1Tag.SEQUENCE
169 */
170 Vector!ubyte putInSequence(ALLOC)(auto const ref Vector!(ubyte, ALLOC) contents)
171 {
172     return DEREncoder()
173             .startCons(ASN1Tag.SEQUENCE)
174             .rawBytes(contents)
175             .endCons()
176             .getContentsUnlocked();
177 }
178 
179 /// ditto
180 Vector!ubyte putInSequence(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) contents)
181 {
182     return DEREncoder()
183             .startCons(ASN1Tag.SEQUENCE)
184             .rawBytes(contents)
185             .endCons()
186             .getContentsUnlocked();
187 }
188 
189 /**
190 * Heuristics tests; is this object possibly BER?
191 * Params:
192 *  source = a data source that will be peeked at but not modified
193 */
194 bool maybeBER(DataSource source)
195 {
196     ubyte first_byte;
197     if (!source.peekByte(first_byte))
198         throw new StreamIOError("maybeBER: Source was empty");
199     
200     if (first_byte == (ASN1Tag.SEQUENCE | ASN1Tag.CONSTRUCTED))
201         return true;
202     return false;
203 }